From 0f335a8135cb0c3965c794e5225eb48bab02fc40 Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Thu, 27 Aug 2026 16:15:02 +0800 Subject: [PATCH] fix(optimizer): fold is_null for native scalars --- src/Optimizer/FuncCallOptimizer.php | 11 ++++- .../type_decl/is-null-native-scalar.phpt | 47 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 tests/compiler/type_decl/is-null-native-scalar.phpt 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)