You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
vm: lower \$obj->prop OP= rhs to OP_OBJECT_COMPOUND_ASSIGN
Compound assigns on object properties (e.g. $obj->n += 5, $obj->s .= ' x')
were delegated to the AST runner via emitAssignViaAST. They now lower to
a dedicated OP_OBJECT_COMPOUND_ASSIGN opcode.
Encoding:
A = const-pool name index (ZString prop name)
B = tokenizer ItemType (e.g. T_PLUS_EQUAL, T_CONCAT_EQUAL)
C bit 0 = "keep value on stack" (expr vs stmt context)
Stack: pops rhs, pops receiver. Inside the handler:
cur := objectGet(receiver, name) (NULL on undefined)
cur := cur.Dup() (bug81705-style snapshot)
res := compoundOp(op)(cur, rhs)
objectSet(receiver, name, res)
if C&1 { push(res) }
Only the static-name, non-nullsafe shape goes native; dynamic-name
\$obj->{\$x} += v and nullsafe \$obj?->prop += v still fall through to
emitAssignViaAST. Typed properties, hooks, and asymmetric visibility are
already handled by the downstream ZObject.ObjectSet, so the native path
inherits them unchanged. Verified locally:
- int/string/nullable compound assigns
- .= with array→string coercion
- typed-prop weak-mode coercion (numeric string warning + float
deprecation notice)
- property hooks fire (set hook called with post-op value)
- expr-context: \$x = (\$obj->n += 100) yields 100
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
0 commit comments