Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

fix(compiler-cli): correctly interpret token arrays in @Injectable deps #43226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from

Conversation

JoostK
Copy link
Member

@JoostK JoostK commented Aug 22, 2021

When specifying the deps array in the @Injectable decorator to
inject dependencies into the injectable's factory function, it should
be possible to use an array literal to configure how the dependency
should be resolved by the DI system.

For example, the following example is allowed:

@Injectable({
  providedIn: 'root',
  useFactory: a => new AppService(a),
  deps: [[new Optional(), 'a']],
})
export class AppService {
  constructor(a) {}
}

Here, the 'a' string token should be injected as optional. However,
the AOT compiler incorrectly used the array literal itself as injection
token, resulting in a failure at runtime. Only if the token were to be
provided using [new Optional(), new Inject('a')] would it work
correctly.

This commit fixes the issue by using the last non-decorator in the
array literal as the token value, instead of the array literal itself.

Note that this is a loose interpretation of array literals: if a token
is omitted from the array literal then the array literal itself is used
as token, but any decorator such as new Optional() would still have
been applied. When there's multiple tokens in the list then only the
last one will be used as actual token, any prior tokens are silently
ignored. This behavior mirrors the JIT interpretation so is kept as is
for now, but may benefit from some stricter checking and better error
reporting in the future.

Fixes #42987


Thanks to @wszgrcy for their contribution.

@JoostK JoostK added target: patch This PR is targeted for the next patch release area: compiler Issues related to `ngc`, Angular's template compiler labels Aug 22, 2021
@ngbot ngbot bot modified the milestone: Backlog Aug 22, 2021
@google-cla

This comment has been minimized.

@google-cla google-cla bot added the cla: no label Aug 22, 2021
@JoostK

This comment has been minimized.

@google-cla
Copy link

google-cla bot commented Aug 22, 2021

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@JoostK
Copy link
Member Author

JoostK commented Aug 22, 2021

@wszgrcy I have added some fixup commits to your commit to get your contribution landed, but would need your explicit consent to get the google-cla bot happy.

@google-cla
Copy link

google-cla bot commented Aug 22, 2021

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@JoostK JoostK force-pushed the ngtsc/di-token-array branch from 78f9ca7 to ca8e65f Compare August 23, 2021 18:17
@google-cla
Copy link

google-cla bot commented Aug 23, 2021

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@wszgrcy
Copy link
Contributor

wszgrcy commented Aug 24, 2021

@googlebot I consent.

@google-cla google-cla bot added cla: yes and removed cla: no labels Aug 24, 2021
@JoostK JoostK marked this pull request as ready for review August 24, 2021 12:40
@JoostK JoostK added the action: review The PR is still awaiting reviews from at least one requested reviewer label Aug 24, 2021
Copy link
Contributor

@petebacondarwin petebacondarwin left a comment

Choose a reason for hiding this comment

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

I kind of feel that we should be less relaxed about the ordering and duplication of tokens in such an array. If not an error then a warning, since it is unlikely that the developer meant to put more than one token into the array.

Apart from that this LGTM.

Comment on lines +318 to +319
if (!isDecorator) {
meta.token = new WrappedNodeExpr(el);
Copy link
Contributor

Choose a reason for hiding this comment

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

This means that the array could be of the form:

['a', new Optional()]

Is this desirable? Or should we require that the token comes after any decorators?

Copy link
Member Author

Choose a reason for hiding this comment

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

This implements the same logic as the runtime; that doesn't necessarily mean that it's desirable but I wouldn't see a reason to disallow this.


@Injectable({
providedIn: 'root',
useFactory: () => new MyAlternateService(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Although this is correct it doesn't really show the intention of using a dependency in the factory.
Perhaps this should be:

Suggested change
useFactory: () => new MyAlternateService(),
useFactory: (dep: SomeDep|null) => new MyAlternateService(dep),

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed.

@petebacondarwin petebacondarwin added action: presubmit The PR is in need of a google3 presubmit and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Sep 21, 2021
@AndrewKushnir
Copy link
Contributor

@JoostK could you please rebase this PR when you get a chance? It looks like it was rebased a while ago and I can not start a presubmit because of that. Thank you.

wszgrcy and others added 4 commits September 24, 2021 21:59
…eps`

When specifying the `deps` array in the `@Injectable` decorator to
inject dependencies into the injectable's factory function, it should
be possible to use an array literal to configure how the dependency
should be resolved by the DI system.

For example, the following example is allowed:

```ts
@Injectable({
  providedIn: 'root',
  useFactory: a => new AppService(a),
  deps: [[new Optional(), 'a']],
})
export class AppService {
  constructor(a) {}
}
```

Here, the `'a'` string token should be injected as optional. However,
the AOT compiler incorrectly used the array literal itself as injection
token, resulting in a failure at runtime. Only if the token were to be
provided using `[new Optional(), new Inject('a')]` would it work
correctly.

This commit fixes the issue by using the last non-decorator in the
array literal as the token value, instead of the array literal itself.

Note that this is a loose interpretation of array literals: if a token
is omitted from the array literal then the array literal itself is used
as token, but any decorator such as `new Optional()` would still have
been applied. When there's multiple tokens in the list then only the
last one will be used as actual token, any prior tokens are silently
ignored. This behavior mirrors the JIT interpretation so is kept as is
for now, but may benefit from some stricter checking and better error
reporting in the future.

Fixes angular#42987
@JoostK JoostK force-pushed the ngtsc/di-token-array branch from ca8e65f to 6fec133 Compare September 24, 2021 20:08
@JoostK
Copy link
Member Author

JoostK commented Sep 24, 2021

I kind of feel that we should be less relaxed about the ordering and duplication of tokens in such an array. If not an error then a warning, since it is unlikely that the developer meant to put more than one token into the array.

I share your feeling that duplication of tokens should be reported as an error (see #42994 (comment) 😄), but strictly speaking that would be a breaking change and separate from this fix.

@JoostK JoostK added the action: merge The PR is ready for merge by the caretaker label Sep 24, 2021
@AndrewKushnir
Copy link
Contributor

Presubmit.

@AndrewKushnir AndrewKushnir removed the action: presubmit The PR is in need of a google3 presubmit label Sep 28, 2021
alxhub pushed a commit that referenced this pull request Sep 28, 2021
…eps` (#43226)

When specifying the `deps` array in the `@Injectable` decorator to
inject dependencies into the injectable's factory function, it should
be possible to use an array literal to configure how the dependency
should be resolved by the DI system.

For example, the following example is allowed:

```ts
@Injectable({
  providedIn: 'root',
  useFactory: a => new AppService(a),
  deps: [[new Optional(), 'a']],
})
export class AppService {
  constructor(a) {}
}
```

Here, the `'a'` string token should be injected as optional. However,
the AOT compiler incorrectly used the array literal itself as injection
token, resulting in a failure at runtime. Only if the token were to be
provided using `[new Optional(), new Inject('a')]` would it work
correctly.

This commit fixes the issue by using the last non-decorator in the
array literal as the token value, instead of the array literal itself.

Note that this is a loose interpretation of array literals: if a token
is omitted from the array literal then the array literal itself is used
as token, but any decorator such as `new Optional()` would still have
been applied. When there's multiple tokens in the list then only the
last one will be used as actual token, any prior tokens are silently
ignored. This behavior mirrors the JIT interpretation so is kept as is
for now, but may benefit from some stricter checking and better error
reporting in the future.

Fixes #42987

PR Close #43226
@alxhub alxhub closed this in 8d2b6af Sep 28, 2021
@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 Oct 29, 2021
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 target: patch This PR is targeted for the next patch release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Injectable with params useFactory and deps(use parameters decorator) throw error
4 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.