Skip to content

fix(compiler): do not leak nested arrow function parameters into the parent scope - #71188

Open
GabeSilvaDev wants to merge 1 commit into
angular:mainfrom
GabeSilvaDev:fix/compiler-nested-arrow-params
Open

GabeSilvaDev wants to merge 1 commit into
angular:mainfrom
GabeSilvaDev:fix/compiler-nested-arrow-params

Conversation

@GabeSilvaDev

Copy link
Copy Markdown
Contributor

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.dev application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

With a component that has a y field, this template throws ReferenceError: y is not defined:

{{ ((x) => twice((y) => y * 2) + y)(1) }}

The last y is outside the inner arrow, so it should read the component's y, and the type checker treats it that way. The generated code is x => ctx.twice(y => y * 2) + y instead. A sibling arrow is affected the same way: in twice((y) => y) + twice((z) => y) the second callback becomes z => y.

updateParameterReferences adds the parameters of every nested arrow function to the set it uses for the root, so any read of those names anywhere in the root becomes a local variable. This came in with 7b5625e, which replaced the per-scope localSymbols with that single pass.

What is the new behavior?

updateParameterReferences now only uses the root's own parameters. Nested arrow functions go through convertAst (and this function) before their parent, so their own parameter reads are already resolved by the time the parent is processed. The example now renders 104 and the sibling case reads ctx.y.

I added a compliance case next to the other arrow function ones and an acceptance test under "arrow functions" in integration_spec.ts. Both fail without the change.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

A parameter named ctx is still shadowed by the generated context parameter (run((ctx) => ctx + y)). That needs a different fix (unique generated names), so I left it out of this PR.

…parent scope

When a template arrow function contained another arrow function, the parameters of the inner one were treated as parameters of the outer one too. A later read with the same name outside the inner function was emitted as a local variable instead of a component property, which threw a ReferenceError at runtime.
@pullapprove
pullapprove Bot requested a review from atscott October 5, 2026 16:26
@angular-robot angular-robot Bot added the area: compiler Issues related to `ngc`, Angular's template compiler label Oct 5, 2026
@ngbot ngbot Bot added this to the Backlog milestone Oct 5, 2026
@JeanMeche
JeanMeche requested review from crisbeto and removed request for atscott October 5, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: compiler Issues related to `ngc`, Angular's template compiler

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant