4343use PHPStan \Type \IntegerType ;
4444use PHPStan \Type \IterableType ;
4545use PHPStan \Type \MixedType ;
46+ use PHPStan \Type \NeverType ;
4647use PHPStan \Type \NonexistentParentClassType ;
4748use PHPStan \Type \NullType ;
4849use PHPStan \Type \ObjectType ;
@@ -325,12 +326,7 @@ public function getType(Expr $node): Type
325326 private function resolveType (Expr $ node ): Type
326327 {
327328 if (
328- $ node instanceof \PhpParser \Node \Expr \BinaryOp \BooleanAnd
329- || $ node instanceof \PhpParser \Node \Expr \BinaryOp \BooleanOr
330- || $ node instanceof \PhpParser \Node \Expr \BinaryOp \LogicalAnd
331- || $ node instanceof \PhpParser \Node \Expr \BinaryOp \LogicalOr
332- || $ node instanceof \PhpParser \Node \Expr \BooleanNot
333- || $ node instanceof \PhpParser \Node \Expr \BinaryOp \LogicalXor
329+ $ node instanceof \PhpParser \Node \Expr \BinaryOp \LogicalXor
334330 || $ node instanceof Expr \BinaryOp \Greater
335331 || $ node instanceof Expr \BinaryOp \GreaterOrEqual
336332 || $ node instanceof Expr \BinaryOp \Smaller
@@ -343,6 +339,79 @@ private function resolveType(Expr $node): Type
343339 return new BooleanType ();
344340 }
345341
342+ if ($ node instanceof \PhpParser \Node \Expr \BooleanNot) {
343+ $ exprBooleanType = $ this ->getType ($ node ->expr )->toBoolean ();
344+ if ($ exprBooleanType instanceof ConstantBooleanType) {
345+ return new ConstantBooleanType (!$ exprBooleanType ->getValue ());
346+ }
347+
348+ return new BooleanType ();
349+ }
350+
351+ if (
352+ $ node instanceof \PhpParser \Node \Expr \BinaryOp \BooleanAnd
353+ || $ node instanceof \PhpParser \Node \Expr \BinaryOp \LogicalAnd
354+ ) {
355+ $ leftBooleanType = $ this ->getType ($ node ->left )->toBoolean ();
356+ if (
357+ $ leftBooleanType instanceof ConstantBooleanType
358+ && !$ leftBooleanType ->getValue ()
359+ ) {
360+ return new ConstantBooleanType (false );
361+ }
362+
363+ $ rightBooleanType = $ this ->filterByTruthyValue ($ node ->left )->getType ($ node ->right )->toBoolean ();
364+ if (
365+ $ rightBooleanType instanceof ConstantBooleanType
366+ && !$ rightBooleanType ->getValue ()
367+ ) {
368+ return new ConstantBooleanType (false );
369+ }
370+
371+ if (
372+ $ leftBooleanType instanceof ConstantBooleanType
373+ && $ leftBooleanType ->getValue ()
374+ && $ rightBooleanType instanceof ConstantBooleanType
375+ && $ rightBooleanType ->getValue ()
376+ ) {
377+ return new ConstantBooleanType (true );
378+ }
379+
380+ return new BooleanType ();
381+ }
382+
383+ if (
384+ $ node instanceof \PhpParser \Node \Expr \BinaryOp \BooleanOr
385+ || $ node instanceof \PhpParser \Node \Expr \BinaryOp \LogicalOr
386+ ) {
387+ $ leftBooleanType = $ this ->getType ($ node ->left )->toBoolean ();
388+ if (
389+ $ leftBooleanType instanceof ConstantBooleanType
390+ && $ leftBooleanType ->getValue ()
391+ ) {
392+ return new ConstantBooleanType (true );
393+ }
394+
395+ $ rightBooleanType = $ this ->filterByFalseyValue ($ node ->left )->getType ($ node ->right )->toBoolean ();
396+ if (
397+ $ rightBooleanType instanceof ConstantBooleanType
398+ && $ rightBooleanType ->getValue ()
399+ ) {
400+ return new ConstantBooleanType (true );
401+ }
402+
403+ if (
404+ $ leftBooleanType instanceof ConstantBooleanType
405+ && !$ leftBooleanType ->getValue ()
406+ && $ rightBooleanType instanceof ConstantBooleanType
407+ && !$ rightBooleanType ->getValue ()
408+ ) {
409+ return new ConstantBooleanType (false );
410+ }
411+
412+ return new BooleanType ();
413+ }
414+
346415 if ($ node instanceof Expr \BinaryOp \Identical) {
347416 $ leftType = $ this ->getType ($ node ->left );
348417 $ rightType = $ this ->getType ($ node ->right );
@@ -390,6 +459,9 @@ private function resolveType(Expr $node): Type
390459 }
391460
392461 $ expressionType = $ this ->getType ($ node ->expr );
462+ if ($ expressionType instanceof NeverType) {
463+ return new ConstantBooleanType (false );
464+ }
393465 $ isExpressionObject = (new ObjectWithoutClassType ())->isSuperTypeOf ($ expressionType );
394466 if (!$ isExpressionObject ->no () && $ type instanceof StringType) {
395467 return new BooleanType ();
0 commit comments