Commit fb1bdd6ff69 for php

commit fb1bdd6ff6968c42cc14bcc24035aefde7367b99
Author: ndossche <7771979+ndossche@users.noreply.github.com>
Date:   Sat Oct 3 13:18:21 2026 +0200

    Fix too wide type inference for ASSIGN_DIM_OP

    The checks for a null result were done on the incorrect variables: t1
    and t2 were already overwritten with the key and value type.
    This results in a null being inferred in the result in cases where this
    isn't possible.

    Closes GH-24092.

diff --git a/NEWS b/NEWS
index 12b88a7e8e6..fd17e6a83fe 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,7 @@ PHP                                                                        NEWS
     root trace at the opcache.jit_max_root_traces limit, causing spurious
     "Too few arguments" errors and crashes). (RV7PR)
   . Fix type inference of ADD_ARRAY_UNPACK with integer keys. (ndossche)
+  . Fix too wide type inference for ASSIGN_DIM_OP. (ndossche)

 - SOAP:
   . Fixed use of uninitialized func in do_request() on OOM bailout.
diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c
index 66369a15482..0c24691ebba 100644
--- a/Zend/Optimizer/zend_inference.c
+++ b/Zend/Optimizer/zend_inference.c
@@ -2809,11 +2809,11 @@ static zend_always_inline zend_result _zend_update_type_info(
 						 * null will be returned. */
 						tmp |= MAY_BE_NULL;
 					}
-					if (t2 & (MAY_BE_ARRAY | MAY_BE_OBJECT)) {
+					if (OP2_INFO() & (MAY_BE_ARRAY | MAY_BE_OBJECT)) {
 						/* Arrays and objects cannot be used as keys. */
 						tmp |= MAY_BE_NULL;
 					}
-					if (t1 & (MAY_BE_ANY - (MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY))) {
+					if (OP1_INFO() & (MAY_BE_ANY - (MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING | MAY_BE_ARRAY))) {
 						/* null and false are implicitly converted to array, anything else
 						 * results in a null return value. */
 						tmp |= MAY_BE_NULL;
diff --git a/ext/opcache/tests/opt/assign_dim_op_result_type.phpt b/ext/opcache/tests/opt/assign_dim_op_result_type.phpt
new file mode 100644
index 00000000000..b449cebdbd9
--- /dev/null
+++ b/ext/opcache/tests/opt/assign_dim_op_result_type.phpt
@@ -0,0 +1,82 @@
+--TEST--
+Type inference of ASSIGN_DIM_OP result uses the container and key types
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.opt_debug_level=0x400000
+opcache.preload=
+--EXTENSIONS--
+opcache
+--FILE--
+<?php
+function f(int $p, int $q, int $k) {
+    $a = [$p, $q];
+    $r = ($a[$k] += 1);
+    return $r;
+}
+
+function g(int $p, int $q, int $k) {
+    $a = [[$p], [$q]];
+    $r = ($a[$k] += [1]);
+    return $r;
+}
+?>
+--EXPECTF--
+$_main:
+     ; (lines=1, args=0, vars=0, tmps=%d, ssa_vars=0, no_loops)
+     ; (after dfa pass)
+     ; %s
+     ; return  [long] RANGE[1..1]
+BB0:
+     ; start exit lines=[0-0]
+     ; level=0
+0000 RETURN int(1)
+
+f:
+     ; (lines=9, args=3, vars=5, tmps=%d, ssa_vars=14, no_loops)
+     ; (after dfa pass)
+     ; %s
+     ; return  [long, double]
+     ; #0.CV0($p) NOVAL [undef]
+     ; #1.CV1($q) NOVAL [undef]
+     ; #2.CV2($k) NOVAL [undef]
+     ; #3.CV3($a) NOVAL [undef]
+     ; #4.CV4($r) NOVAL [undef]
+BB0:
+     ; start exit lines=[0-8]
+     ; level=0
+0000 #5.CV0($p) [long] RANGE[MIN..MAX] = RECV 1
+0001 #6.CV1($q) [long] RANGE[MIN..MAX] = RECV 2
+0002 #7.CV2($k) [long] RANGE[MIN..MAX] = RECV 3
+0003 #8.T5 NOESC [[packed, hash] array [long] of [long]] = INIT_ARRAY 2 (packed) #5.CV0($p) [long] RANGE[MIN..MAX] NEXT
+0004 ADD_ARRAY_ELEMENT #6.CV1($q) [long] RANGE[MIN..MAX] NEXT #8.T5 NOESC [[packed, hash] array [long] of [long]] -> #9.T5 NOESC [[packed, hash] array [long] of [long]]
+0005 #10.CV3($a) NOESC [[packed, hash] array [long] of [long]] = QM_ASSIGN #9.T5 NOESC [[packed, hash] array [long] of [long]]
+0006 #13.CV4($r) [long, double] = ASSIGN_DIM_OP (ADD) #10.CV3($a) NOESC [[packed, hash] array [long] of [long]] -> #11.CV3($a) NOVAL NOESC [[packed, hash] array [long] of [long, double]] #7.CV2($k) [long] RANGE[MIN..MAX]
+0007 OP_DATA int(1)
+0008 RETURN #13.CV4($r) [long, double]
+
+g:
+     ; (lines=11, args=3, vars=5, tmps=%d, ssa_vars=16, no_loops)
+     ; (after dfa pass)
+     ; %s
+     ; return  [long, double, array of [any, ref]]
+     ; #0.CV0($p) NOVAL [undef]
+     ; #1.CV1($q) NOVAL [undef]
+     ; #2.CV2($k) NOVAL [undef]
+     ; #3.CV3($a) NOVAL [undef]
+     ; #4.CV4($r) NOVAL [undef]
+BB0:
+     ; start exit lines=[0-10]
+     ; level=0
+0000 #5.CV0($p) [long] RANGE[MIN..MAX] = RECV 1
+0001 #6.CV1($q) [long] RANGE[MIN..MAX] = RECV 2
+0002 #7.CV2($k) [long] RANGE[MIN..MAX] = RECV 3
+0003 #8.T5 NOESC [[packed, hash] array [long] of [long]] = INIT_ARRAY 1 (packed) #5.CV0($p) [long] RANGE[MIN..MAX] NEXT
+0004 #9.T6 NOESC [[packed, hash] array [long] of [array]] = INIT_ARRAY 2 (packed) #8.T5 NOESC [[packed, hash] array [long] of [long]] NEXT
+0005 #10.T7 NOESC [[packed, hash] array [long] of [long]] = INIT_ARRAY 1 (packed) #6.CV1($q) [long] RANGE[MIN..MAX] NEXT
+0006 ADD_ARRAY_ELEMENT #10.T7 NOESC [[packed, hash] array [long] of [long]] NEXT #9.T6 NOESC [[packed, hash] array [long] of [array]] -> #11.T6 NOESC [[packed, hash] array [long] of [array]]
+0007 #12.CV3($a) NOESC [[packed, hash] array [long] of [array]] = QM_ASSIGN #11.T6 NOESC [[packed, hash] array [long] of [array]]
+0008 #15.CV4($r) [long, double, array of [any, ref]] = ASSIGN_DIM_OP (ADD) #12.CV3($a) NOESC [[packed, hash] array [long] of [array]] -> #13.CV3($a) NOVAL NOESC [[packed, hash] array [long] of [long, double, array]] #7.CV2($k) [long] RANGE[MIN..MAX]
+0009 OP_DATA array(...)
+0010 RETURN #15.CV4($r) [long, double, array of [any, ref]]