Skip to content

Do not create a throw point for void returned by dynamic throw type extensions - #6515

Merged
ondrejmirtes merged 1 commit into
2.2.xfrom
dynamic-throw-type-extension-void
Sep 22, 2026
Merged

ondrejmirtes merged 1 commit into
2.2.xfrom
dynamic-throw-type-extension-void

Conversation

@ondrejmirtes

Copy link
Copy Markdown
Member

Returning VoidType from a DynamicFunctionThrowTypeExtension, DynamicMethodThrowTypeExtension or DynamicStaticMethodThrowTypeExtension (also for new) created an explicit throw point of type void, instead of saying that the call does not throw. As a result:

  • a variable assigned in the try block was only maybe-defined in finally,
  • catch (\Throwable $e) around the call was not reported as dead,
  • a function with @throws void calling it was reported with throws exception void but the PHPDoc contains @throws void,
  • custom rules that look at explicit throw points ($throwPoint->isExplicit()) saw a throw.

Ds\Map::get() / remove() with a default value (DsMapDynamicMethodThrowTypeExtension) are affected today.

A @throws void declaration without an extension already produces no throw point (FuncCallHandler::getFunctionThrowPoint() skips it when $throwType->isVoid()->yes()). This PR does the same in the extension branches of FuncCallHandler, MethodThrowPointHelper and NewHandler.

This is groundwork for the upcoming throw type extensions for functions that PhpStorm stubs now declare as throwing ValueError and similar (min()/max(), sprintf(), ...). They will return VoidType when the call cannot throw.

Tests:

  • DynamicMethodThrowTypeExtensionTest with new test extensions returning VoidType for a function, a method, a static method and a constructor (variable certainty in finally)
  • CatchWithUnthrownExceptionRuleTest::testDsMapVoidThrowType() for the real Ds\Map extension

Both fail without the change.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Dhb4ssXuKVWcVBcNFpsdn7

…xtensions

A dynamic function, method or static method throw type extension returning
VoidType produced an explicit throw point of type void. It kept variables
assigned in a try block only maybe-defined in finally, kept catch (Throwable)
alive, made rules iterating explicit throw points see a throw, and was reported
as "throws exception void" in functions with @throws void. Treat it as no
throw point, the same way a @throws void declaration is treated.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dhb4ssXuKVWcVBcNFpsdn7
@ondrejmirtes
ondrejmirtes merged commit 265f2b0 into 2.2.x Sep 22, 2026
243 of 246 checks passed
@ondrejmirtes
ondrejmirtes deleted the dynamic-throw-type-extension-void branch September 22, 2026 09:15
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