Skip to content

[4.x]: preloadSingles breaks the spread operator #14783

@MoritzLost

Description

@MoritzLost

What happened?

Description

I'm trying to use the spread operator introduced in Twig 3.8.0. However, with the preloadSingles option enabled, the operator doesn't work as intended. Test case:

{% set one = { one: 'two' } %}
{% set two = {
    ...one,
    foo: 'bar',
} %}
{% dd two %}

Example on Twig Fiddle

This should result in a flat array with keys one and foo. It does if preloadSingles is disabled. If the setting is enabled, you get a nested array instead.

Steps to reproduce

  1. Put the snippet above in your template and enable preloadSingles.

Expected behavior

The behaviour with preloadSingles enabled should match the default behaviour.

Actual behavior

There seems to be an issue with the way Craft overwrites Twig's built-in nodes. You can see the issue in the generated templates:

With preloadSingles enabled:

        $macros = $this->macros;
        craft\helpers\Template::beginProfile("template", "elements/entries/home");
        craft\helpers\Template::preloadSingles(['one', 'two']);
        // line 1
        $context["one"] = ["one" => "two"];
        // line 2
        $context["two"] = [        // line 3
(isset($context["one"]) || array_key_exists("one", $context) ? $context["one"] : (craft\helpers\Template::fallbackExists("one") ? craft\helpers\Template::fallback("one") : (function () { throw new RuntimeError('Variable "one" does not exist.', 3, $this->source); })())), "foo" => "bar"];
        // line 6
        Craft::dd((isset($context["two"]) || array_key_exists("two", $context) ? $context["two"] : (craft\helpers\Template::fallbackExists("two") ? craft\helpers\Template::fallback("two") : (function () { throw new RuntimeError('Variable "two" does not exist.', 6, $this->source); })())));
        craft\helpers\Template::endProfile("template", "elements/entries/home");

Without preloadSingles:

        craft\helpers\Template::beginProfile("template", "elements/entries/home");
        // line 1
        $context["one"] = ["one" => "two"];
        // line 2
        $context["two"] = [...        // line 3
(isset($context["one"]) || array_key_exists("one", $context) ? $context["one"] : (function () { throw new RuntimeError('Variable "one" does not exist.', 3, $this->source); })()), "foo" => "bar"];
        // line 6
        Craft::dd((isset($context["two"]) || array_key_exists("two", $context) ? $context["two"] : (function () { throw new RuntimeError('Variable "two" does not exist.', 6, $this->source); })()));
        craft\helpers\Template::endProfile("template", "elements/entries/home");

With preloadSingles, the spread operator (...) is missing from the compiled expression.

Craft CMS version

4.8.8

PHP version

8.2

Operating system and version

No response

Database type and version

No response

Image driver and version

No response

Installed plugins and versions

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions