diff --git a/src/Optimizer/FuncCallOptimizer.php b/src/Optimizer/FuncCallOptimizer.php index 8f80987c..e5572bdc 100644 --- a/src/Optimizer/FuncCallOptimizer.php +++ b/src/Optimizer/FuncCallOptimizer.php @@ -693,7 +693,16 @@ trait FuncCallOptimizer if ($this->isNativeObjectClass($this->detectClassOfExpr($value))) { return '(' . $this->parseExprAsValue($value) . ' == nullptr)'; } - return '(' . $this->parseExprAsValue($value) . ').isNull()'; + + $type = $this->detectTypeOfExpr($value); + $valueCode = $this->parseExprAsValue($value); + if ($this->isNativeType($type)) { + // Fixed native scalars cannot contain null. Keep evaluating the + // operand because a call or increment may still have side effects. + return '((void) (' . $valueCode . '), false)'; + } + + return '(' . $valueCode . ').isNull()'; } protected function genIsCallable(string $n, Node\Expr\FuncCall $e, array $c): string|false diff --git a/tests/compiler/type_decl/is-null-native-scalar.phpt b/tests/compiler/type_decl/is-null-native-scalar.phpt new file mode 100644 index 00000000..4e936d8e --- /dev/null +++ b/tests/compiler/type_decl/is-null-native-scalar.phpt @@ -0,0 +1,47 @@ +--TEST-- +is_null returns false for fixed native scalars and preserves operand side effects +--FILE-- + +--EXPECT-- +bool(false) +bool(false) +bool(false) +bool(false) +emitInt +bool(false) +bool(true) +bool(false)