# 4.0.0 (2026-XX-XX)

 * Remove `TemplateVariable` and `AssignTemplateVariable`; use `MacroVariable` and `AssignMacroVariable` instead
 * Add the `isAlwaysAllowedInSandbox()` method to `Twig\TwigCallableInterface` and `Twig\TokenParser\TokenParserInterface`
 * Always allow printing a `Markup` object in a sandbox, whatever the security policy is
 * Remove the `Twig\Sandbox\SourcePolicyInterface` interface and the corresponding argument of `Twig\Extension\SandboxExtension::__construct()`
 * Remove the `sandboxed` argument of the `include` function, use the `render_sandboxed` function instead
 * Remove `Twig\Extension\SandboxExtension::enableSandbox()`, `disableSandbox()`, and `isSandboxedGlobally()`, use `Twig\Sandbox\Sandbox` instead
 * Enforce the `parent`, `block`, and `attribute` functions against the sandbox `allowedFunctions` allow-list
 * Enforce tests against the sandbox `allowedTests` allow-list and add the `$allowedTests` argument to `Twig\Sandbox\SecurityPolicy::__construct()`
 * Add a fourth `array $tests` argument to `Twig\Sandbox\SecurityPolicyInterface::checkSecurity()`
 * Throw a `SyntaxError` when an `extends`, `use`, or `macro` tag is not at the root of a template
 * Throw a `SyntaxError` when a macro is defined more than once in a template
 * Throw a `SyntaxError` when calling a macro without parentheses
 * Throw a `SyntaxError` when testing a macro with the `defined` test using parentheses
 * Remove support for case-insensitive macro references
 * Remove support for resolving macros through legacy `macro_`-prefixed references
 * Remove support for omitted, extra, and unknown macro arguments unless accepted by defaults or an explicit variadic argument
 * Remove the implicit `varargs` macro variable; use an explicit variadic argument instead
 * Remove support for extending `Twig\Node\MacroNode`
 * Remove support for passing invalid node types to `Twig\Node\MacroNode` and `Twig\Node\ModuleNode`

# 4.0.0 alpha 1 (2026-05-17)

 * Make the `raw` filter sticky
 * Add back the `if` condition on `for` loops
 * Add return types to all ExtensionInterface methods (`getFunctions()`, `getFilters()`, etc.)
 * Add support for recursive loops (via the `loop()` function)
 * Add `loop.changed`, `loop.previous`, `loop.next`, and `loop.cycle` variables
 * Make `loop.last` always available (even for non-countable iterators)
 * Change the compilation of `for` loops to throw an exception when a `loop.*` variable is not defined
 * Make `Environment::getGlobals()` private
 * Drop support for PHP < 8.2
 * Escape characters are no longer ignored
