Skip to content

fix(compiler): allow banana-in-a-box bindings to end with non-null assertion#37809

Closed
JoostK wants to merge 1 commit intoangular:masterfrom
JoostK:non-null-two-way-bindings
Closed

fix(compiler): allow banana-in-a-box bindings to end with non-null assertion#37809
JoostK wants to merge 1 commit intoangular:masterfrom
JoostK:non-null-two-way-bindings

Conversation

@JoostK
Copy link
Member

@JoostK JoostK commented Jun 28, 2020

For two-way-bindings that use the banana-in-a-box syntax, the compiler
synthesizes an event assignment expression from the primary expression.
It is valid for the primary expression to be terminated by the non-null
operator, however naive string substitution is used for the synthesized
expression, such that the ! would immediately precede the = token,
resulting in the valid != operator token. The expression would still
parse correctly but it doesn't implement the proper semantics, resulting
in incorrect runtime behavior.

Changing the expression substitution to force a space between the
primary expression and the assignment avoids this mistake, but it
uncovers a new issue. The grammar does not allow for the LHS of an
assignment to be the non-null operator, so the synthesized expression
would fail to parse. To alleviate this, the synthesized expression is
parsed with a special parser flag to allow for this syntax.

Fixes #36551


Implementation note: it is up for debate whether extending the grammar to accept more expressions as LHS of an assignment would be desirable for regular output bindings. I choose not to change the grammar at this moment, as it seems like a change that needs to be introduced in at least a minor. Additionally, I feel like the whole expression substitution is a bit of a hack in the first place, so an alternative way of handling this case may be desirable in the future. To allow for this cleanup, I feel like it's best to wait for VE removal as the parser infrastructure is currently quite convoluted.

@JoostK JoostK added type: bug/fix freq1: low severity3: broken workaround2: non-obvious target: patch This PR is targeted for the next patch release risk: low area: compiler Issues related to `ngc`, Angular's template compiler labels Jun 28, 2020
@ngbot ngbot bot modified the milestone: needsTriage Jun 28, 2020
@JoostK JoostK force-pushed the non-null-two-way-bindings branch from ab42126 to 1abd5c6 Compare June 28, 2020 18:41
@JoostK JoostK marked this pull request as ready for review June 28, 2020 21:45
@JoostK JoostK requested review from alxhub and ayazhafiz June 28, 2020 21:46
@JoostK JoostK added the action: review The PR is still awaiting reviews from at least one requested reviewer label Jun 29, 2020
Copy link
Contributor

@ayazhafiz ayazhafiz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice fix!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the comment is unnecessary now

Suggested change
ParseFlags.None /* parseFlags */, this.errors, 0 /* relative offset */);
ParseFlags.None, this.errors, 0 /* relative offset */);

Comment on lines 914 to 966
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message isn't incorrect, but I think I better message would mention that the non-null assertion operator cannot appear on the LHS of an assignment expression. If this sounds reasonable, could you add a todo here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, I added a note here. It's really not that hard to have a specialized error message, however I'd rather not touch this at the moment (especially if we do want to support this syntax)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, makes sense

@JoostK JoostK force-pushed the non-null-two-way-bindings branch from 1abd5c6 to 491678d Compare July 4, 2020 14:45
@alxhub
Copy link
Member

alxhub commented Jul 10, 2020

Presubmit

@JoostK JoostK force-pushed the non-null-two-way-bindings branch from 491678d to 4e7a212 Compare August 3, 2020 19:32
@alxhub
Copy link
Member

alxhub commented Aug 3, 2020

And again

@alxhub
Copy link
Member

alxhub commented Aug 4, 2020

The g3 failure here is legitimate, as this does break codelyzer internally, due to the extra parameter added to parseAction. Let's sync up on this.

@alxhub
Copy link
Member

alxhub commented Aug 6, 2020

@JoostK we can fix this internally just by patching codelyzer. Can you test this change with angular-eslint (the spiritual successor) and verify that no external fixes are needed there?

@jessicajaniuk
Copy link
Contributor

@JoostK Looks like this PR stalled. Any idea what the status is here and whether we still plan on landing it?

@JoostK JoostK force-pushed the non-null-two-way-bindings branch from 4e7a212 to d241b0b Compare May 4, 2021 20:05
@JoostK
Copy link
Member Author

JoostK commented May 4, 2021

Picking this one up again. This was rebased on latest master and I tested the build artefacts in angular-eslint (on its master branch after updating to v12 RC releases) and there were no issues there (which is to be expected as they don't touch lower level parse API, unlike Codelyzer).

@JoostK JoostK added state: blocked and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Jul 29, 2021
@ngbot ngbot bot removed this from the needsTriage milestone Jul 29, 2021
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Whether an assignment event is parsed, i.e. an expression originating from two-way-binding
* Whether an assignment event is being parsed, i.e. an expression originating from two-way-binding

@AndrewKushnir AndrewKushnir added the action: presubmit The PR is in need of a google3 presubmit label Nov 4, 2021
@AndrewKushnir
Copy link
Contributor

Presubmit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a quick comment above this enum on what it represents?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you plz add a quick comment here to provide more context on why we have 2 advance calls?

@angular angular deleted a comment Nov 5, 2021
@angular angular deleted a comment Nov 5, 2021
@AndrewKushnir
Copy link
Contributor

Global Presubmit.

@AndrewKushnir
Copy link
Contributor

@JoostK FYI the most recent TGP is fully "green" (internal-only link) with this change: there are no issues with Codelyzer. I don't have an access to Alex's test runs (the results are no longer available), but I believe TGP should've triggered Codelyzer-related targets.

@alxhub I've also looked at the Codelyzer folder and didn't notice any updates that make it compatible with this change. So I'm wondering if we should run more tests or we can proceed with caution (merge and sync the change as a separate commit, be ready to rollback). What do you think?

@AndrewKushnir AndrewKushnir removed the action: presubmit The PR is in need of a google3 presubmit label Nov 5, 2021
@JoostK JoostK force-pushed the non-null-two-way-bindings branch from 5c1335a to 8b4bf90 Compare November 5, 2021 16:56
@JoostK JoostK force-pushed the non-null-two-way-bindings branch 2 times, most recently from cdc9bc2 to 2d86518 Compare January 16, 2022 20:50
@jessicajaniuk
Copy link
Contributor

@JoostK Can you rebase this to resolve the conflicts and ping me when you do? We'll run another TGP and see how it goes. Hopefully we can land this.

@jessicajaniuk jessicajaniuk modified the milestones: Backlog, v14-candidates Feb 4, 2022
@jessicajaniuk jessicajaniuk added the action: presubmit The PR is in need of a google3 presubmit label Feb 4, 2022
…sertion

For two-way-bindings that use the banana-in-a-box syntax, the compiler
synthesizes an event assignment expression from the primary expression.
It is valid for the primary expression to be terminated by the non-null
operator, however naive string substitution is used for the synthesized
expression, such that the `!` would immediately precede the `=` token,
resulting in the valid `!=` operator token. The expression would still
parse correctly but it doesn't implement the proper semantics, resulting
in incorrect runtime behavior.

Changing the expression substitution to force a space between the
primary expression and the assignment avoids this mistake, but it
uncovers a new issue. The grammar does not allow for the LHS of an
assignment to be the non-null operator, so the synthesized expression
would fail to parse. To alleviate this, the synthesized expression is
parsed with a special parser flag to allow for this syntax.

Fixes angular#36551
@JoostK JoostK force-pushed the non-null-two-way-bindings branch from 2d86518 to 9751bcb Compare February 4, 2022 12:55
@JoostK JoostK added action: merge The PR is ready for merge by the caretaker and removed state: blocked labels Feb 4, 2022
@JoostK
Copy link
Member Author

JoostK commented Feb 4, 2022

Rebased and added to the merge queue 👍

@AndrewKushnir
Copy link
Contributor

Started a new TGP.

@AndrewKushnir AndrewKushnir removed the action: presubmit The PR is in need of a google3 presubmit label Feb 7, 2022
@AndrewKushnir
Copy link
Contributor

TGP is "green" :) Adding this PR to the merge queue...

@dylhunn
Copy link
Contributor

dylhunn commented Feb 7, 2022

This PR was merged into the repository by commit db6cf7e.

@dylhunn dylhunn closed this in db6cf7e Feb 7, 2022
dylhunn pushed a commit that referenced this pull request Feb 7, 2022
…sertion (#37809)

For two-way-bindings that use the banana-in-a-box syntax, the compiler
synthesizes an event assignment expression from the primary expression.
It is valid for the primary expression to be terminated by the non-null
operator, however naive string substitution is used for the synthesized
expression, such that the `!` would immediately precede the `=` token,
resulting in the valid `!=` operator token. The expression would still
parse correctly but it doesn't implement the proper semantics, resulting
in incorrect runtime behavior.

Changing the expression substitution to force a space between the
primary expression and the assignment avoids this mistake, but it
uncovers a new issue. The grammar does not allow for the LHS of an
assignment to be the non-null operator, so the synthesized expression
would fail to parse. To alleviate this, the synthesized expression is
parsed with a special parser flag to allow for this syntax.

Fixes #36551

PR Close #37809
crapStone pushed a commit to Calciumdibromid/CaBr2 that referenced this pull request Feb 15, 2022
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [@angular/animations](https://github.com/angular/angular) | dependencies | patch | [`13.2.1` -> `13.2.2`](https://renovatebot.com/diffs/npm/@angular%2fanimations/13.2.1/13.2.2) |
| [@angular/common](https://github.com/angular/angular) | dependencies | patch | [`13.2.1` -> `13.2.2`](https://renovatebot.com/diffs/npm/@angular%2fcommon/13.2.1/13.2.2) |
| [@angular/compiler](https://github.com/angular/angular) | dependencies | patch | [`13.2.1` -> `13.2.2`](https://renovatebot.com/diffs/npm/@angular%2fcompiler/13.2.1/13.2.2) |
| [@angular/compiler-cli](https://github.com/angular/angular) | devDependencies | patch | [`13.2.1` -> `13.2.2`](https://renovatebot.com/diffs/npm/@angular%2fcompiler-cli/13.2.1/13.2.2) |
| [@angular/core](https://github.com/angular/angular) | dependencies | patch | [`13.2.1` -> `13.2.2`](https://renovatebot.com/diffs/npm/@angular%2fcore/13.2.1/13.2.2) |
| [@angular/forms](https://github.com/angular/angular) | dependencies | patch | [`13.2.1` -> `13.2.2`](https://renovatebot.com/diffs/npm/@angular%2fforms/13.2.1/13.2.2) |
| [@angular/platform-browser](https://github.com/angular/angular) | dependencies | patch | [`13.2.1` -> `13.2.2`](https://renovatebot.com/diffs/npm/@angular%2fplatform-browser/13.2.1/13.2.2) |
| [@angular/platform-browser-dynamic](https://github.com/angular/angular) | dependencies | patch | [`13.2.1` -> `13.2.2`](https://renovatebot.com/diffs/npm/@angular%2fplatform-browser-dynamic/13.2.1/13.2.2) |
| [@angular/router](https://github.com/angular/angular) | dependencies | patch | [`13.2.1` -> `13.2.2`](https://renovatebot.com/diffs/npm/@angular%2frouter/13.2.1/13.2.2) |

---

### Release Notes

<details>
<summary>angular/angular</summary>

### [`v13.2.2`](https://github.com/angular/angular/blob/HEAD/CHANGELOG.md#&#8203;1322-2022-02-08)

[Compare Source](angular/angular@13.2.1...13.2.2)

##### compiler

| Commit | Type | Description |
| -- | -- | -- |
| [37af6abb49](angular/angular@37af6ab) | fix | allow banana-in-a-box bindings to end with non-null assertion ([#&#8203;37809](angular/angular#37809)) |

##### forms

| Commit | Type | Description |
| -- | -- | -- |
| [b75e90f809](angular/angular@b75e90f) | fix | incorrectly keeping track of ngModel with ngFor inside a form ([#&#8203;40459](angular/angular#40459)) |

##### http

| Commit | Type | Description |
| -- | -- | -- |
| [3fae6637e7](angular/angular@3fae663) | perf | remove IE special status handling ([#&#8203;44354](angular/angular#44354)) |

##### upgrade

| Commit | Type | Description |
| -- | -- | -- |
| [b9aab0c87b](angular/angular@b9aab0c) | fix | Do not trigger duplicate navigation events from Angular Router ([#&#8203;43441](angular/angular#43441)) |

#### Special Thanks

Alan Agius, Alan Cohen, Andrew Kushnir, Andrew Scott, Daniel Díaz, Dario Piotrowicz, Doug Parker, Jayson Acosta, Joey Perrott, JoostK, Kristiyan Kostadinov, Olivier Capuozzo, Ramzan, Shai Reznik, TANMAY SRIVASTAVA, dario-piotrowicz, iRealNirmal, jhonyeduardo, mgechev and zuckjet

<!-- CHANGELOG SPLIT MARKER -->

</details>

---

### Configuration

📅 **Schedule**: At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, click this checkbox.

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).

Co-authored-by: cabr2-bot <cabr2.help@gmail.com>
Reviewed-on: https://codeberg.org/Calciumdibromid/CaBr2/pulls/1160
Reviewed-by: Epsilon_02 <epsilon_02@noreply.codeberg.org>
Co-authored-by: Calciumdibromid Bot <cabr2_bot@noreply.codeberg.org>
Co-committed-by: Calciumdibromid Bot <cabr2_bot@noreply.codeberg.org>
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Mar 10, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

action: merge The PR is ready for merge by the caretaker area: compiler Issues related to `ngc`, Angular's template compiler cla: yes freq1: low risk: low target: patch This PR is targeted for the next patch release type: bug/fix workaround2: non-obvious

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Two-way binding not work with non-null assertion operator

9 participants