{"record":{"id":"50658a283132d239","repo":"twigphp/Twig","slug":"left-side-must-be-arrayexpression-for-object-mapping","errorCode":null,"errorMessage":"Left side must be ArrayExpression for object/mapping destructuring.","messagePattern":"Left side must be ArrayExpression for object/mapping destructuring\\.","errorType":"exception","errorClass":"LogicException","httpStatus":null,"severity":"error","filePath":"src/Node/Expression/Binary/ObjectDestructuringSetBinary.php","lineNumber":37,"sourceCode":"use Twig\\Node\\Expression\\Variable\\AssignContextVariable;\nuse Twig\\Node\\Node;\n\n/**\n * @internal\n */\nclass ObjectDestructuringSetBinary extends AbstractBinary\n{\n    /** @var list<array{property: string, variable: string}> */\n    private array $mappings = [];\n\n    /**\n     * @param ArrayExpression    $left  The array expression containing object/mapping destructuring properties\n     * @param AbstractExpression $right The expression providing values for assignment\n     */\n    public function __construct(Node $left, Node $right, int $lineno)\n    {\n        if (!$left instanceof ArrayExpression) {\n            throw new \\LogicException('Left side must be ArrayExpression for object/mapping destructuring.');\n        }\n        foreach ($left->getKeyValuePairs() as $pair) {\n            if (!$pair['value'] instanceof AssignContextVariable) {\n                throw new SyntaxError(\\sprintf('Cannot assign to \"%s\", only variables can be assigned in object/mapping destructuring.', $pair['value']::class), $lineno);\n            }\n\n            $this->mappings[] = [\n                'property' => $pair['key']->getAttribute('value'),\n                'variable' => $pair['value']->getAttribute('name'),\n            ];\n        }\n\n        parent::__construct($left, $right, $lineno);\n    }\n\n    public function compile(Compiler $compiler): void\n    {\n        $compiler->addDebugInfo($this);","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/twigphp/Twig/blob/a414c3a491defb5a60f2fc88ef79ff37c90010cd/src/Node/Expression/Binary/ObjectDestructuringSetBinary.php#L19-L55","documentation":"This node compiles object/mapping destructuring assignments (e.g. {a, b} = expr in Twig expression syntax). Its constructor contract requires the left side to be an ArrayExpression containing the destructuring pattern; anything else (a NameExpression, a literal, etc.) is a parser-level contract violation, so a LogicException is thrown at node construction time.","triggerScenarios":"Constructing ObjectDestructuringSetBinary directly with a non-ArrayExpression first argument; a custom expression parser producing a destructuring Set node without first parsing the left-hand side into an ArrayExpression of key/value pairs; misuse when adapting the parser to new syntax.","commonSituations":"Custom Twig operators/parsers (e.g. via an extension adding destructuring-like syntax) passing the wrong node type; template syntax parsed by a modified grammar where the LHS wasn't wrapped in an array expression; library version drift where the node class API changed.","solutions":["Ensure the left operand is an ArrayExpression built from the parsed pattern before constructing the node.","Each pair's 'value' must be an AssignContextVariable — fix the parser so identifiers become AssignContextVariable nodes.","If the LHS is a simple variable assignment, use the plain SetBinary node instead of the destructuring one.","Catch the LogicException at parser/extension construction to surface which syntax produced the malformed LHS."],"exampleFix":"// before\n$node = new ObjectDestructuringSetBinary($nameExpr, $rhs, $line); // $nameExpr is a NameExpression\n// after\n$pattern = new ArrayExpression($pairs, $line); // pairs whose values are AssignContextVariable\n$node = new ObjectDestructuringSetBinary($pattern, $rhs, $line);","handlingStrategy":"type-guard","validationCode":"if (!$left instanceof \\Twig\\Node\\Expression\\ArrayExpression) {\n    throw new \\SyntaxError('Object/mapping destructuring requires an array-expression pattern on the left.', $lineno);\n}","typeGuard":"function isDestructuringPattern(\\Twig\\Node\\Node $n): bool { return $n instanceof \\Twig\\Node\\Expression\\ArrayExpression; }","tryCatchPattern":"try {\n    $node = new ObjectDestructuringSetBinary($left, $right, $lineno);\n} catch (\\LogicException $e) {\n    // LHS wasn't an ArrayExpression — fall back to plain SetBinary or raise a SyntaxError\n}","preventionTips":["Always parse the destructuring pattern into ArrayExpression first.","Ensure every pair value is an AssignContextVariable before building the node.","Add parser unit tests covering both destructuring and plain assignment LHS."],"tags":["php","twig","ast","destructuring","parser"],"backgroundTag":"type-mismatch","analyzedSha":"a414c3a491defb5a60f2fc88ef79ff37c90010cd","analyzedAt":"2026-09-13T15:10:46.849Z","contentChangedAt":"2026-09-13T15:10:46.849Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}