Skip to content

fix(compiler-cli): dom property binding check in signal extended diagnostic#54324

Closed
cexbrayat wants to merge 1 commit intoangular:mainfrom
cexbrayat:fix/dom-property-bound-signal-not-invoked
Closed

fix(compiler-cli): dom property binding check in signal extended diagnostic#54324
cexbrayat wants to merge 1 commit intoangular:mainfrom
cexbrayat:fix/dom-property-bound-signal-not-invoked

Conversation

@cexbrayat
Copy link
Member

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.io application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Currently, we have no warning when forgetting to call a signal in dom property binding

<div [id]="mySignal"></div>

What is the new behavior?

The compiler now checks if a signal is properly called on dom property bindings. The ideal solution would be for the compiler to check if dom property bindings in general are properly typed, but this is currently not the case, and it is a bigger task to land this change (see #54098).

In the meantime, we can maybe use the extended diagnostic for interpolated signals to catch these issues.
Obviously the name of the diagnostic is no longer accurate, but this PR is to start a discussion.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

@cexbrayat cexbrayat marked this pull request as draft February 7, 2024 20:50
@devversion devversion self-assigned this Feb 7, 2024
@cexbrayat cexbrayat force-pushed the fix/dom-property-bound-signal-not-invoked branch from e3fdd9a to 3b828db Compare February 7, 2024 21:44
Copy link
Member

Choose a reason for hiding this comment

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

Can we have a test to ensure this doesn't throw an error is id is a model() ?

Copy link
Member Author

Choose a reason for hiding this comment

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

For now, it does throw if id is a model, in addition to the compiler error that will complain about the incompatible type between WritableSignal<number> and number, see authoring_spec.ts below.

This is a draft PR that we'll adjust, it's just to start a discussion after what we discussed with @devversion
We're not yet sure if this is a good idea

Copy link
Member

Choose a reason for hiding this comment

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

Sounds like this is fine? I do see the problem where an input accepts a Signal reference. We are breaking these cases, while arguably one should never pass around a signal, "aside" from using two-way binding syntax.

Copy link
Member

Choose a reason for hiding this comment

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

I remember that we didn't want to do it initially (see #49660) as there a legitimate of passing signals. model() inputs are one of them.

Copy link
Member

@devversion devversion Feb 7, 2024

Choose a reason for hiding this comment

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

With recent changes of the AST, we should be able to skip two way data bindings I think. With this approach we are just trying to solve this in the intermediary until we can rely on proper DOM type checking (or a combination of both checks)

@devversion devversion added area: compiler Issues related to `ngc`, Angular's template compiler core: inputs / outputs labels Feb 7, 2024
@ngbot ngbot bot added this to the Backlog milestone Feb 7, 2024
@cexbrayat cexbrayat force-pushed the fix/dom-property-bound-signal-not-invoked branch from 3b828db to 97801dd Compare April 16, 2024 15:48
@cexbrayat cexbrayat marked this pull request as ready for review April 16, 2024 15:48
@cexbrayat cexbrayat force-pushed the fix/dom-property-bound-signal-not-invoked branch from 97801dd to 68d831e Compare April 16, 2024 15:52
Copy link
Member

Choose a reason for hiding this comment

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

Sounds like this is fine? I do see the problem where an input accepts a Signal reference. We are breaking these cases, while arguably one should never pass around a signal, "aside" from using two-way binding syntax.

Copy link
Member

Choose a reason for hiding this comment

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

I believe the migration could check the target of the expression, so that we can skip property bindings to inputs?

Copy link
Member Author

Choose a reason for hiding this comment

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

Do you know what should we check to see that? The binding type doesn't allow us to know as far as I can see.

Copy link
Member

Choose a reason for hiding this comment

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

IIRC there is a getExpressionTarget method

Copy link
Member Author

Choose a reason for hiding this comment

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

I think I've got something working using the symbol of the node and checking if it is an input. I amended the PR if you want to take a look.

@cexbrayat cexbrayat force-pushed the fix/dom-property-bound-signal-not-invoked branch 2 times, most recently from 34c641f to f870e46 Compare April 18, 2024 12:47
Copy link
Member

@devversion devversion left a comment

Choose a reason for hiding this comment

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

Awesome work! Thanks @cexbrayat

@devversion devversion added action: merge The PR is ready for merge by the caretaker target: patch This PR is targeted for the next patch release labels Apr 18, 2024
@ngbot

This comment was marked as outdated.

@devversion devversion removed the action: merge The PR is ready for merge by the caretaker label Apr 18, 2024
@devversion
Copy link
Member

FYI: This seems to break some internal targets:

Error: Unexpected expression for signal input write type.
    at template_symbol_builder_unwrapSignalInputWriteTAccessor
    at SymbolBuilder.getSymbolOfInputBinding

@cexbrayat
Copy link
Member Author

@devversion Is this something you're looking into?

@devversion
Copy link
Member

@cexbrayat I won't have time currently, but can help providing as much details as possible. My guess is that the symbol retrieval is triggered on some unexpected AST node. Will have a look at the templates

@cexbrayat
Copy link
Member Author

@devversion Did you have time to take a look at the templates which broke the internal targets?

@devversion
Copy link
Member

@cexbrayat The template looks pretty simple and fine. All inputs are targeting signal inputs— so that's good. At least the error is somewhat "reasonable".

Can you print what type of node we get in https://github.com/angular/angular/blob/main/packages/compiler-cli/src/ngtsc/typecheck/src/template_symbol_builder.ts#L796-L803? Maybe using ts.SyntaxKind[theActualKind] so that we can re-run with more debug information? Potentially this is a bug for the language service.

@cexbrayat cexbrayat force-pushed the fix/dom-property-bound-signal-not-invoked branch from f870e46 to febf14a Compare May 7, 2024 17:31
@angular-robot angular-robot bot requested a review from devversion May 7, 2024 17:31
@cexbrayat
Copy link
Member Author

@devversion I pushed a new commit with a log, let me know if that helps

@devversion
Copy link
Member

devversion commented May 8, 2024

@cexbrayat Thanks. Hmm. This didn't help a lot: actual SyntaxKind Identifier.

It sounds like some input in the type check block code is directly accessed. in form of. e.g. x[ɵINPUT_SIGNAL_BRAND_WRITE_TYPE], while we expect dir.inputField[ɵINPUT_SIGNAL_BRAND_WRITE_TYPE]

I should probably debug this further, but sharing some early information here, as much as I can.

@devversion
Copy link
Member

I think the assumption of the receiver being e.g. a property access is simply not correct. There are cases, e.g. with honorAccessModifiersForInputBindings = false where we don't generate this "pattern" and this suddenly fails now. I will send a fix for this, then we can re-run.

@devversion
Copy link
Member

@cexbrayat sent a fix. Note that I think that relying on getSymbolOfNode might not be 100% valid, but it's probably fine? I.e. it might bind to an input, but we simply don't return a symbol yet. Same for @Input (you cannot jump to these inputs with the VSCode extension)

devversion added a commit to devversion/angular that referenced this pull request May 13, 2024
… input with restricted access

Currently when attempting to retrieve a TCB symbol for an input binding
that refers to a signal input with e.g. `protected`, while the
`honorAccessModifiersForInputBindings` flag is `false`, Angular will
throw a runtime exception because the symbol retrieval code always
expects a proper field access in the TCB.

This is not the case with `honorAccessModifiersForInputBindings =
false`, as TCB will allocate a temporary variable when ignoring the
field access. This will then trigger the runtime exception (which we
added to flag such "unexpected" cases). This commit handles it
gracefully, as it's valid TCB, but we simply cannot generate a proper
TCB symbol (yet). This is similar to `@Input` decorator inputs.

In the future we may implement logic to build up TCB symbols for
non-property access bindings, for both signal inputs or `@Input`
inputs. This commit just avoids a build exception.

Related to: angular#54324.
atscott pushed a commit that referenced this pull request May 16, 2024
… input with restricted access (#55774)

Currently when attempting to retrieve a TCB symbol for an input binding
that refers to a signal input with e.g. `protected`, while the
`honorAccessModifiersForInputBindings` flag is `false`, Angular will
throw a runtime exception because the symbol retrieval code always
expects a proper field access in the TCB.

This is not the case with `honorAccessModifiersForInputBindings =
false`, as TCB will allocate a temporary variable when ignoring the
field access. This will then trigger the runtime exception (which we
added to flag such "unexpected" cases). This commit handles it
gracefully, as it's valid TCB, but we simply cannot generate a proper
TCB symbol (yet). This is similar to `@Input` decorator inputs.

In the future we may implement logic to build up TCB symbols for
non-property access bindings, for both signal inputs or `@Input`
inputs. This commit just avoids a build exception.

Related to: #54324.

PR Close #55774
atscott pushed a commit that referenced this pull request May 16, 2024
… input with restricted access (#55774)

Currently when attempting to retrieve a TCB symbol for an input binding
that refers to a signal input with e.g. `protected`, while the
`honorAccessModifiersForInputBindings` flag is `false`, Angular will
throw a runtime exception because the symbol retrieval code always
expects a proper field access in the TCB.

This is not the case with `honorAccessModifiersForInputBindings =
false`, as TCB will allocate a temporary variable when ignoring the
field access. This will then trigger the runtime exception (which we
added to flag such "unexpected" cases). This commit handles it
gracefully, as it's valid TCB, but we simply cannot generate a proper
TCB symbol (yet). This is similar to `@Input` decorator inputs.

In the future we may implement logic to build up TCB symbols for
non-property access bindings, for both signal inputs or `@Input`
inputs. This commit just avoids a build exception.

Related to: #54324.

PR Close #55774
@cexbrayat cexbrayat force-pushed the fix/dom-property-bound-signal-not-invoked branch from febf14a to 7b66fad Compare May 16, 2024 17:50
…nostic

The compiler now checks if a signal is properly called on dom property bindings.
The ideal solution would be for the compiler to check if dom property bindings in general are properly typed,
but this is currently not the case, and it is a bigger task to land this change.
In the meantime, the signal diagnostic is augmented to catch cases like the following:

```
<div [id]="mySignal"></div>
```
@cexbrayat cexbrayat force-pushed the fix/dom-property-bound-signal-not-invoked branch from 7b66fad to d93ae67 Compare May 16, 2024 17:57
@cexbrayat
Copy link
Member Author

@devversion I rebased on main now that your PR has been merged

@devversion
Copy link
Member

@cexbrayat Thx. I'm running a presubmit and TGP now.

@devversion
Copy link
Member

TGP

@devversion devversion added action: merge The PR is ready for merge by the caretaker target: minor This PR is targeted for the next minor release target: rc This PR is targeted for the next release-candidate and removed target: patch This PR is targeted for the next patch release target: minor This PR is targeted for the next minor release labels May 17, 2024
@dylhunn
Copy link
Contributor

dylhunn commented May 21, 2024

This PR was merged into the repository by commit 237eaca.

dylhunn pushed a commit that referenced this pull request May 21, 2024
…nostic (#54324)

The compiler now checks if a signal is properly called on dom property bindings.
The ideal solution would be for the compiler to check if dom property bindings in general are properly typed,
but this is currently not the case, and it is a bigger task to land this change.
In the meantime, the signal diagnostic is augmented to catch cases like the following:

```
<div [id]="mySignal"></div>
```

PR Close #54324
@dylhunn dylhunn closed this in 237eaca May 21, 2024
@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 Jun 21, 2024
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 core: inputs / outputs target: rc This PR is targeted for the next release-candidate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants