This PR was squashed before being merged into the 3.x branch.
Discussion
----------
Catch errors thrown during template rendering
Some errors, like not providing a function the proper number of arguments or division by zero, extend from `\Error` rather than `\Exception`. This PR catches these types of errors during template rendering and throws a `RuntimeError` in order to provide better debugging information.
Commits
-------
85bf01b4 Catch errors thrown during template rendering
This PR was merged into the 3.x branch.
Discussion
----------
Add `@codeCoverageIgnore` to untestable compiled methods
I've been experimenting with adding my compiled templates to my code coverage reports and it works largely as expected. Templates that get executed return percentages accurate to the number of lines the tests actually cover. The only exception are the "meta" methods on the compiled template that aren't necessarily called by the tests.
This PR adds ``@codeCoverageIgnore`` comments to the compiled template for all non-display methods so the coverage report only lists lines from `doDisplay`.
I'm assuming that I will need to update some of the Twig tests to account for these new comments, but am curious if you'd be open to this change.
An example screenshot below. The last line shows line 46 out of the compiled template is never executed. The compiled template's `getDebugInfo` even correctly informs me that line 46 maps to line 4 in my `.twig` so I'll work on updating the line numbering next.

Commits
-------
1cf610bd Add `@codeCoverageIgnore` to untestable compiled methods
This PR was merged into the 3.x branch.
Discussion
----------
Compile Elvis operator into Elvis operator `?:`
When using ternary operator without "then" part, the "condition" part is evaluated twice, which is inconsistent with how PHP works.
The Twig template `A ?: B` is currently compiled as `A ? A : B` in PHP. This PR change it to `A ?: B`.
If `A` is a complex expression, it improves performance to only execute the expression once.
If `A` is has a side effect (like updating a variable), the expression being executed twice could result in a bug. ([example in PHP](https://3v4l.org/LWZLR))
Example with ``@WebProfiler`/Collector/form.html.twig` [line 9](https://github.com/symfony/symfony/blob/e6d1ed4edb5ae197ec7d25ddaf64cfa456229504/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/form.html.twig#L9) (see deep [diff](https://www.diffchecker.com/jOm3dE13/))
```twig
{{ collector.data.nb_errors ?: collector.data.forms|length }}
```
Previous compilation:
```php
echo twig_escape_filter($this->env, (((isset($context["error_count"]) || array_key_exists("error_count", $context) ? $context["error_count"] : (function () { throw new RuntimeError('Variable "error_count" does not exist.', 9, $this->source); })())) ? ((isset($context["error_count"]) || array_key_exists("error_count", $context) ? $context["error_count"] : (function () { throw new RuntimeError('Variable "error_count" does not exist.', 9, $this->source); })())) : (twig_get_attribute($this->env, $this->source, (isset($context["collector"]) || array_key_exists("collector", $context) ? $context["collector"] : (function () { throw new RuntimeError('Variable "collector" does not exist.', 9, $this->source); })()), "countDefines", [], "any", false, false, false, 9))), "html", null, true);
```
After this change:
```php
echo twig_escape_filter($this->env, ((isset($context["error_count"]) || array_key_exists("error_count", $context) ? $context["error_count"] : (function () { throw new RuntimeError('Variable "error_count" does not exist.', 9, $this->source); })()) ?: twig_get_attribute($this->env, $this->source, (isset($context["collector"]) || array_key_exists("collector", $context) ? $context["collector"] : (function () { throw new RuntimeError('Variable "collector" does not exist.', 9, $this->source); })()), "countDefines", [], "any", false, false, false, 9)), "html", null, true);
```
Commits
-------
fb0d7495 Compile Elvis operator with Elvis operator
This PR was merged into the 3.x branch.
Discussion
----------
Update signature to acknowledge a TemplateWrapper
`$name` legitimately can be of type `Twig\TemplateWrapper`. This is already considered in line 1331. This PR updates the method signature in the PHPDoc.
This PR is necessary because other developers may rely on the signature, see contao/contao#6169.
Commits
-------
b0cabc09 Update signature to acknowledge a TemplateWrapper
This PR was merged into the 3.x branch.
Discussion
----------
Use PHP 8.0 functions with polyfill
Backport some changes from #3881 into 3.x using `symfony/polyfill-php80`.
- `str_starts_with`
- `str_ends_with`
- `str_contains`
- `get_debug_type`
Benefits:
- Less conflicts when both 3.x and 4.x branches will be maintained.
- Performance gain for PHP 8.0+ ([83,7% of installs](https://packagist.org/packages/twig/twig/php-stats#3))
Commits
-------
1d5c0928 Use PHP 8.0 functions with polyfill
This PR was merged into the 3.x branch.
Discussion
----------
Remove `TemplateWrapper::render()` 2nd parameter not used
The 2nd virtual parameter of `TemplateWrapper::render()` was added by #2805.
`Template::render()` don't define and don't use this 2nd parameter.
Running the test suite, this method never get more than 1 parameter (I assumed it could be used by the compiled Template via the backtrace, but it isn't).
Commits
-------
c56b87b4 Remove TemplateWrapper::render 2nd parameter not used
This PR was merged into the 3.x branch.
Discussion
----------
Remove unused variables and unreachable code
I did some archaeology to find the origin of each useless line of code. Details in comments.
Commits
-------
6d715e20 Remove unused variables and unreachable code
This PR was squashed before being merged into the 3.x branch.
Discussion
----------
Adding support for the ...spread operator on arrays and hashes
Hi!
Long time user, first time contributor of a real future. I hope I didn't miss anything - but this seemed quite straightforward in the end.
Notes:
* In PHP 7.3 or lower, using the spread operator will result in a Twig syntax error.
* In 8.0 or lower, using the spread operator on a hash will result in a Twig syntax error.
fabbot failures are unrelated, so I'm not touching them.
Cheers!
Commits
-------
ba4fe3ba Adding support for the ...spread operator on arrays and hashes