@@ -1658,6 +1658,12 @@ class ConstantArrayType
16581658 zval *k = keyTypes ();
16591659 zval *v = k != NULL ? valueTypes () : NULL ;
16601660 if (UNEXPECTED (result.isUndef () || v == NULL )) return zv::Val ();
1661+ /* $acceptsValueCache = [] — keyed by both object handles in one
1662+ * integer instead of the twin's 'id-id' string */
1663+ zval acceptsValueCacheZv;
1664+ array_init (&acceptsValueCacheZv);
1665+ zv::Val acceptsValueCacheHolder = zv::Val::adopt (acceptsValueCacheZv);
1666+ HashTable *acceptsValueCache = Z_ARRVAL (acceptsValueCacheZv);
16611667 for (zv::ArrayEntry entry : zv::ArrRef (k)) {
16621668 zend_long i = (zend_long) entry.indexKey ();
16631669 zval *keyType = entry.value ().deref ().raw ();
@@ -1702,11 +1708,34 @@ class ConstantArrayType
17021708 if (UNEXPECTED (result.isUndef ())) return zv::Val ();
17031709 zv::Val otherValueType = callType (Z_OBJ_P (type), PT_LC (" getoffsetvaluetype" ), 1 , keyType);
17041710 if (UNEXPECTED (otherValueType.isUndef ())) return zv::Val ();
1711+ zend_ulong acceptsValueCacheKey = ((zend_ulong) Z_OBJ_HANDLE_P (valueType) << 32 ) | (zend_ulong) Z_OBJ_HANDLE_P (otherValueType.raw ());
1712+ zv::Val acceptsValue;
1713+ zval *acceptsValueCached = zend_hash_index_find (acceptsValueCache, acceptsValueCacheKey);
1714+ if (acceptsValueCached != NULL ) {
1715+ acceptsValue = zv::Val::copyOf (zv::Ref (zend_hash_index_find (Z_ARRVAL_P (acceptsValueCached), 1 )));
1716+ } else {
1717+ zv::Args args{otherValueType.raw (), strictTypes};
1718+ acceptsValue = pt_type_op (Z_OBJ_P (valueType), PT_OP_ACCEPTS , 2 , args);
1719+ if (UNEXPECTED (acceptsValue.isUndef ())) return zv::Val ();
1720+ /* $otherValueType is kept alive so that its id is not reused */
1721+ zval pair;
1722+ array_init_size (&pair, 2 );
1723+ Z_TRY_ADDREF_P (otherValueType.raw ());
1724+ add_next_index_zval (&pair, otherValueType.raw ());
1725+ Z_TRY_ADDREF_P (acceptsValue.raw ());
1726+ add_next_index_zval (&pair, acceptsValue.raw ());
1727+ zend_hash_index_update (acceptsValueCache, acceptsValueCacheKey, &pair);
1728+ }
1729+ /* $acceptsValue->yes() && count($acceptsValue->reasons) === 0: continue */
1730+ zend_long acceptsValueBefore = pt_type_result_trinary (acceptsValue.raw ());
1731+ if (UNEXPECTED (acceptsValueBefore < 0 )) return zv::Val ();
1732+ if (acceptsValueBefore == PT_TRI_YES ) {
1733+ zv::Val acceptsValueReasons = resultReasons (acceptsValue.raw ());
1734+ if (UNEXPECTED (acceptsValueReasons.isUndef ())) return zv::Val ();
1735+ if (arrayCount (acceptsValueReasons.raw ()) == 0 ) continue ;
1736+ }
17051737 zv::Val verbosity = pt_type_verbosity_recommended (valueType, otherValueType.raw ());
17061738 if (UNEXPECTED (verbosity.isUndef ())) return zv::Val ();
1707- zv::Args args{otherValueType.raw (), strictTypes};
1708- zv::Val acceptsValue = pt_type_op (Z_OBJ_P (valueType), PT_OP_ACCEPTS , 2 , args);
1709- if (UNEXPECTED (acceptsValue.isUndef ())) return zv::Val ();
17101739 zv::Val captured = quadOf (keyType, valueType, verbosity.raw (), otherValueType.raw ());
17111740 acceptsValue = decorateReasons (acceptsValue.raw (), offsetReasonCallback, captured.raw (), NULL );
17121741 if (UNEXPECTED (acceptsValue.isUndef ())) return zv::Val ();
0 commit comments