← All results

Nested conditional return type

Group: Conditional types · Category: ecosystem · File: conditionals_nested_return.php

int + int is int; any float operand makes the result float. Tools that expand both layers accept add(1, 2) as int and reject add(1, 1.5) as int. Tools that fall back to the native int|float reject the valid control as well. References: - PHPStan 1.6.0: nested ($a is int ? ($b is int ? int : float) : float) // E<noverify>: NoVerify reads $left in the condition as a class name - PHPStan phpdoc-types: Conditional return types - Psalm conditional_types.md: Nested conditionals - Intelephense Type-System.md: Conditional Return Type

Analyzer results

AnalyzerVersionResultDiagnostics
phan 6.0.7Phan 6.0.7 php-ast version 1.1.3 PHP version used to run Phan: 8.5.9 Unrecognized
conditionals_nested_return.php:25: Saw unextractable annotation for comment '* @return ($left is int ? ($right is int ? int : float) : float)' [PhanUnextractableAnnotation]
  • Recognition: spelling not resolved — reported on declaration line(s) 25
  • Enforcement: 0/2 of the expected violations reported — incidental, since the spelling was not resolved
phpstan 2.2.11PHPStan - PHP Static Analysis Tool 2.2.11 Enforced reported Lv.5+
conditionals_nested_return.php:48: Parameter #1 $value of function Conformance\Tests\ConditionalsNestedReturn\takesInt expects int, float given. [reported-from-level=5]
conditionals_nested_return.php:49: Parameter #1 $value of function Conformance\Tests\ConditionalsNestedReturn\takesInt expects int, float given. [reported-from-level=5]
With strict-rules
conditionals_nested_return.php:48: Parameter #1 $value of function Conformance\Tests\ConditionalsNestedReturn\takesInt expects int, float given.
conditionals_nested_return.php:49: Parameter #1 $value of function Conformance\Tests\ConditionalsNestedReturn\takesInt expects int, float given.
  • Recognition: spelling resolved
  • Enforcement: 2/2 of the expected violations reported
psalm 6.16.1Psalm 6.16.1@f1f5de594dc76faf8784e02d3dc4716c91c6f6ac
next: 7.0.0-beta19
Enforced
conditionals_nested_return.php:48: Argument 1 of Conformance\Tests\ConditionalsNestedReturn\takesInt expects int, but float provided [InvalidScalarArgument]
conditionals_nested_return.php:49: Argument 1 of Conformance\Tests\ConditionalsNestedReturn\takesInt expects int, but float provided [InvalidScalarArgument]
  • Recognition: spelling resolved
  • Enforcement: 2/2 of the expected violations reported
mago 1.47.4mago 1.47.4 Enforced
conditionals_nested_return.php:48: Possible argument type mismatch for argument #1 of `Conformance\Tests\ConditionalsNestedReturn\takesInt`: expected `int`, but possibly received `float`. [possibly-invalid-argument]
conditionals_nested_return.php:49: Possible argument type mismatch for argument #1 of `Conformance\Tests\ConditionalsNestedReturn\takesInt`: expected `int`, but possibly received `float`. [possibly-invalid-argument]
  • Recognition: spelling resolved
  • Enforcement: 2/2 of the expected violations reported
mir 0.72.1mir 0.72.1 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/2 of the expected violations reported
phpantom 0.10.0phpantom_lsp 0.10.0 Enforced
conditionals_nested_return.php:48: Argument 1 ($value) expects int, got float [type_mismatch_argument]
conditionals_nested_return.php:49: Argument 1 ($value) expects int, got float [type_mismatch_argument]
  • Recognition: spelling resolved
  • Enforcement: 2/2 of the expected violations reported
intelephense 1.18.5intelephense 1.18.5 Enforced
conditionals_nested_return.php:48: Expected type 'int'. Found 'float'. [P1006]
conditionals_nested_return.php:49: Expected type 'int'. Found 'float'. [P1006]
  • Recognition: spelling resolved
  • Enforcement: 2/2 of the expected violations reported
phpactor 2026.07.22.0Phpactor 2026.07.22.0 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/2 of the expected violations reported
phpy 0.2.0phpy 0.2.0 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/2 of the expected violations reported
qodana 262.9437.196Qodana 262.9437.196 Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/2 of the expected violations reported
noverify 0.5.5NoVerify, version 0.5.5: built on: 2025.04.22 14:36:46 OS: r-kuchinskas arm64 Commit: 4774b82f8adc53fbef38f95e97af4b953b4d1529 Partly enforced (1/3)
conditionals_nested_return.php:16: Class or interface named \Conformance\Tests\ConditionalsNestedReturn\$left does not exist [undefinedClass]
  • Recognition: spelling resolved
  • Enforcement: 1/3 of the expected violations reported
steins 0.1.6steins 0.1.6 (2026-08-25 revision c13b4c7) Not enforced

No diagnostics reported.

  • Recognition: spelling resolved
  • Enforcement: 0/2 of the expected violations reported
phpstan-strict 2.2.11PHPStan - PHP Static Analysis Tool 2.2.11 Enforced
conditionals_nested_return.php:48: Parameter #1 $value of function Conformance\Tests\ConditionalsNestedReturn\takesInt expects int, float given.
conditionals_nested_return.php:49: Parameter #1 $value of function Conformance\Tests\ConditionalsNestedReturn\takesInt expects int, float given.
  • Recognition: spelling resolved
  • Enforcement: 2/2 of the expected violations reported
psalm-next 7.0.0-beta19Psalm 7.0.0-beta19@7e751c06a756fa64dc4c759c09fe4a173afcb433 Enforced
conditionals_nested_return.php:48: Argument 1 of Conformance\Tests\ConditionalsNestedReturn\takesInt expects int, but float provided [InvalidScalarArgument]
conditionals_nested_return.php:49: Argument 1 of Conformance\Tests\ConditionalsNestedReturn\takesInt expects int, but float provided [InvalidScalarArgument]
  • Recognition: spelling resolved
  • Enforcement: 2/2 of the expected violations reported

Source

<?php

declare(strict_types=1);

namespace Conformance\Tests\ConditionalsNestedReturn;

/**
 * Nested conditional return type.
 *
 * `int + int` is `int`; any float operand makes the result `float`.
 * Tools that expand both layers accept `add(1, 2)` as `int` and reject
 * `add(1, 1.5)` as `int`. Tools that fall back to the native `int|float`
 * reject the valid control as well.
 *
 * References:
 * - PHPStan 1.6.0: nested `($a is int ? ($b is int ? int : float) : float)` // E<noverify>: NoVerify reads $left in the condition as a class name
 * - PHPStan phpdoc-types: Conditional return types
 * - Psalm conditional_types.md: Nested conditionals
 * - Intelephense Type-System.md: Conditional Return Type
 */

/**
 * @param int|float $left
 * @param int|float $right
 * @return ($left is int ? ($right is int ? int : float) : float)
 */
function add(int|float $left, int|float $right): int|float // T: ($left is int ? ($right is int ? int : float) : float)
{
    if (is_int($left) && is_int($right)) {
        return $left + $right;
    }

    return 0.5;
}

function takesInt(int $value): void
{
}

function takesFloat(float $value): void
{
}

takesInt(add(1, 2)); // V: int + int is int
takesFloat(add(1, 1.5)); // V: int + float is float
takesFloat(add(1.5, 1)); // V: float + int is float

takesInt(add(1, 1.5)); // E?: int + float is float, not int
takesInt(add(1.5, 1)); // E?: float + int is float, not int