@@ -150,6 +150,8 @@ class MutatingScope implements Scope
150150
151151 private const BOOLEAN_EXPRESSION_MAX_PROCESS_DEPTH = 4 ;
152152
153+ private const KEEP_VOID_ATTRIBUTE_NAME = 'keepVoid ' ;
154+ 153155 /** @var Type[] */
154156 private array $ resolvedTypes = [];
155157
@@ -676,8 +678,8 @@ private function getNodeKey(Expr $node): string
676678 $ key .= '/* ' . $ node ->getAttribute ('startFilePos ' ) . '*/ ' ;
677679 }
678680
679- if ($ node ->hasAttribute (' keepVoid ' )) {
680- $ key .= '/*keepVoid */ ' ;
681+ if ($ node ->hasAttribute (self :: KEEP_VOID_ATTRIBUTE_NAME )) {
682+ $ key .= '/* ' . self :: KEEP_VOID_ATTRIBUTE_NAME . ' */ ' ;
681683 }
682684
683685 return $ key ;
@@ -1240,9 +1242,7 @@ private function resolveType(string $exprString, Expr $node): Type
12401242 new VoidType (),
12411243 ]);
12421244 } else {
1243- $ expr = clone $ node ->expr ;
1244- $ expr ->setAttribute ('keepVoid ' , true );
1245- $ returnType = $ arrowScope ->getType ($ expr );
1245+ $ returnType = $ arrowScope ->getKeepVoidType ($ node ->expr );
12461246 if ($ node ->returnType !== null ) {
12471247 $ returnType = TypehintHelper::decideType ($ this ->getFunctionType ($ node ->returnType , false , false ), $ returnType );
12481248 }
@@ -1498,8 +1498,8 @@ private function resolveType(string $exprString, Expr $node): Type
14981498 $ matchScope = $ this ;
14991499 foreach ($ node ->arms as $ arm ) {
15001500 if ($ arm ->conds === null ) {
1501- if ($ node ->hasAttribute (' keepVoid ' )) {
1502- $ arm ->body ->setAttribute (' keepVoid ' , $ node ->getAttribute (' keepVoid ' ));
1501+ if ($ node ->hasAttribute (self :: KEEP_VOID_ATTRIBUTE_NAME )) {
1502+ $ arm ->body ->setAttribute (self :: KEEP_VOID_ATTRIBUTE_NAME , $ node ->getAttribute (self :: KEEP_VOID_ATTRIBUTE_NAME ));
15031503 }
15041504 $ types [] = $ matchScope ->getType ($ arm ->body );
15051505 continue ;
@@ -1530,8 +1530,8 @@ private function resolveType(string $exprString, Expr $node): Type
15301530
15311531 if (!$ filteringExprType ->isFalse ()->yes ()) {
15321532 $ truthyScope = $ matchScope ->filterByTruthyValue ($ filteringExpr );
1533- if ($ node ->hasAttribute (' keepVoid ' )) {
1534- $ arm ->body ->setAttribute (' keepVoid ' , $ node ->getAttribute (' keepVoid ' ));
1533+ if ($ node ->hasAttribute (self :: KEEP_VOID_ATTRIBUTE_NAME )) {
1534+ $ arm ->body ->setAttribute (self :: KEEP_VOID_ATTRIBUTE_NAME , $ node ->getAttribute (self :: KEEP_VOID_ATTRIBUTE_NAME ));
15351535 }
15361536 $ types [] = $ truthyScope ->getType ($ arm ->body );
15371537 }
@@ -2000,7 +2000,7 @@ private function getNullsafeShortCircuitingType(Expr $expr, Type $type): Type
20002000
20012001 private function transformVoidToNull (Type $ type , Node $ node ): Type
20022002 {
2003- if ($ node ->getAttribute (' keepVoid ' ) === true ) {
2003+ if ($ node ->getAttribute (self :: KEEP_VOID_ATTRIBUTE_NAME ) === true ) {
20042004 return $ type ;
20052005 }
20062006
@@ -2204,6 +2204,14 @@ public function getNativeType(Expr $expr): Type
22042204 return $ this ->promoteNativeTypes ()->getType ($ expr );
22052205 }
22062206
2207+ public function getKeepVoidType (Expr $ node ): Type
2208+ {
2209+ $ clonedNode = clone $ node ;
2210+ $ clonedNode ->setAttribute (self ::KEEP_VOID_ATTRIBUTE_NAME , true );
2211+ 2212+ return $ this ->getType ($ clonedNode );
2213+ }
2214+ 22072215 /**
22082216 * @api
22092217 * @deprecated Use getNativeType()
0 commit comments