Skip to content
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

feat(compiler-cli): exclude abstract classes from `strictInjectionPar… #44615

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

JoostK
Copy link
Member

@JoostK JoostK commented Jan 4, 2022

…ameters` requirement

In AOT compilations, the strictInjectionParameters compiler option can
be enabled to report errors when an @Injectable annotated class has a
constructor with parameters that do not provide an injection token, e.g.
only a primitive type or interface.

Since Ivy it's become required that any class with Angular behavior
(e.g. the ngOnDestroy lifecycle hook) is decorated using an Angular
decorator, which meant that @Injectable() may need to have been added
to abstract base classes. Doing so would then report an error if
strictInjectionParameters is enabled, if the abstract class has an
incompatible constructor for DI purposes. This may be fine though, as
a subclass may call the constructor explicitly without relying on
Angular's DI mechanism.

Therefore, this commit excludes abstract classes from the
strictInjectionParameters check. This avoids an error from being
reported at compile time. If the constructor ends up being used by
Angular's DI system at runtime, then the factory function of the
abstract class will throw an error by means of the ɵɵinvalidFactory
instruction.

Closes #37914

@JoostK JoostK added feature comp: compiler target: minor labels Jan 4, 2022
@ngbot ngbot bot added this to the Backlog milestone Jan 4, 2022
@ngbot ngbot bot added this to the Backlog milestone Jan 4, 2022
@ngbot ngbot bot added this to the Backlog milestone Jan 4, 2022
@JoostK JoostK force-pushed the ngtsc/di/strict-params-abstract branch 2 times, most recently from 72cc61c to 7f30792 Compare Mar 23, 2022
expect(diags[0].code).toBe(ngErrorCode(ErrorCode.DIRECTIVE_INHERITS_UNDECORATED_CTOR));
expect(diags[0].messageText)
.toEqual(
`The directive AbstractMiddleDir inherits its constructor from ParentClass, but the latter does not have an Angular decorator of its own. Dependency injection will not be able to resolve the parameters of ParentClass's constructor. Either add a @Directive decorator to ParentClass, or add an explicit constructor to AbstractMiddleDir.`);
Copy link
Member Author

@JoostK JoostK Mar 23, 2022

Choose a reason for hiding this comment

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

We used to report this report this error for abstract classes and I haven't changed this, but I'm wondering if we should exempt abstract directives from this error.

@Injectable({ providedIn: 'root', useValue: null })
export class UseValueService extends ParentService {}

@Injectable({ providedIn: 'root', useClass: ConcreteServiceWithCtor })
Copy link
Member Author

@JoostK JoostK Mar 23, 2022

Choose a reason for hiding this comment

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

Interestingly, we don't check useClass here like we check providers in the providers array! 😱

@JoostK JoostK force-pushed the ngtsc/di/strict-params-abstract branch 3 times, most recently from efbc3f0 to b1db475 Compare Apr 25, 2022
@JoostK JoostK marked this pull request as ready for review Apr 25, 2022
jessicajaniuk
jessicajaniuk previously approved these changes Apr 26, 2022
Copy link
Contributor

@jessicajaniuk jessicajaniuk left a comment

reviewed-for: public-api

@pullapprove pullapprove bot requested a review from dylhunn Apr 26, 2022
@AndrewKushnir AndrewKushnir removed this from the Backlog milestone Apr 27, 2022
@AndrewKushnir AndrewKushnir added this to the v14-candidates milestone Apr 27, 2022
@JoostK JoostK force-pushed the ngtsc/di/strict-params-abstract branch from b1db475 to 7be53d8 Compare Apr 27, 2022
@dylhunn
Copy link
Contributor

@dylhunn dylhunn commented May 2, 2022

@JoostK It looks like this hasn't been updated in a while. Is this a PR we'd like to merge for 14?

@JoostK
Copy link
Member Author

@JoostK JoostK commented May 2, 2022

@JoostK It looks like this hasn't been updated in a while. Is this a PR we'd like to merge for 14?

It's ready to go from my side, just awaiting review. I'm afraid we're short on time to get this LGTM'd in time.

atscott
atscott approved these changes May 2, 2022
const ctorDeps = getConstructorDependencies(declaration, this.host, this.isCore);
return {
ctorDeps: unwrapConstructorDependencies(ctorDeps),
};
}
Copy link
Contributor

@atscott atscott May 2, 2022

Choose a reason for hiding this comment

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

Should this call registerInjectable before returning?

Copy link
Member Author

@JoostK JoostK May 3, 2022

Choose a reason for hiding this comment

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

Hmm yeah that might make sense to avoid potential repeated work 👍

AndrewKushnir
AndrewKushnir previously approved these changes May 2, 2022
Copy link
Contributor

@AndrewKushnir AndrewKushnir left a comment

Reviewed-for: public-api

@pullapprove pullapprove bot requested a review from atscott May 2, 2022
dylhunn
dylhunn previously approved these changes May 2, 2022
Copy link
Contributor

@dylhunn dylhunn left a comment

reviewed-for: public-api

atscott
atscott previously approved these changes May 3, 2022
Copy link
Contributor

@atscott atscott left a comment

reviewed-for: public-api

quick note: I would might classify this as a fix. I don't think the distinction will matter if it gets merged before the feature freeze for v14

@atscott atscott added action: merge and removed action: review labels May 3, 2022
@ngbot
Copy link

@ngbot ngbot bot commented May 3, 2022

I see that you just added the action: merge label, but the following checks are still failing:
    failure status "ci/circleci: test_angular_devtools" is failing
    pending 1 pending code review

If you want your PR to be merged, it has to pass all the CI checks.

If you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help.

@JoostK JoostK dismissed stale reviews from atscott, dylhunn, and AndrewKushnir via a703061 May 3, 2022
@JoostK JoostK force-pushed the ngtsc/di/strict-params-abstract branch from 7be53d8 to a703061 Compare May 3, 2022
@dylhunn
Copy link
Contributor

@dylhunn dylhunn commented May 3, 2022

This PR was merged into the repository by commit 9cf14ff.

@dylhunn dylhunn closed this in 9cf14ff May 3, 2022
dylhunn added a commit to dylhunn/angular that referenced this issue May 3, 2022
@dylhunn dylhunn reopened this May 3, 2022
@dylhunn
Copy link
Contributor

@dylhunn dylhunn commented May 3, 2022

We have to roll this back due to breakage in g3. This will likely need forward fixes in order to land.

@AndrewKushnir AndrewKushnir added state: blocked and removed action: merge labels May 3, 2022
dylhunn added a commit that referenced this issue May 4, 2022
…ctionParameters` requirement (#44615)" (#45862)

This reverts commit 9cf14ff.

PR Close #45862
@alxhub alxhub removed this from the v14-candidates milestone May 4, 2022
@ngbot ngbot bot added this to the Backlog milestone May 4, 2022
…meters` requirement

In AOT compilations, the `strictInjectionParameters` compiler option can
be enabled to report errors when an `@Injectable` annotated class has a
constructor with parameters that do not provide an injection token, e.g.
only a primitive type or interface.

Since Ivy it's become required that any class with Angular behavior
(e.g. the `ngOnDestroy` lifecycle hook) is decorated using an Angular
decorator, which meant that `@Injectable()` may need to have been added
to abstract base classes. Doing so would then report an error if
`strictInjectionParameters` is enabled, if the abstract class has an
incompatible constructor for DI purposes. This may be fine though, as
a subclass may call the constructor explicitly without relying on
Angular's DI mechanism.

Therefore, this commit excludes abstract classes from the
`strictInjectionParameters` check. This avoids an error from being
reported at compile time. If the constructor ends up being used by
Angular's DI system at runtime, then the factory function of the
abstract class will throw an error by means of the `ɵɵinvalidFactory`
instruction.

In addition to the runtime error, this commit also analyzes the inheritance
chain of an injectable without a constructor to verify that their inherited
constructor is valid.

Closes angular#37914
@JoostK JoostK force-pushed the ngtsc/di/strict-params-abstract branch from a703061 to b0ba89e Compare May 4, 2022
@JoostK JoostK added target: rc and removed feature target: minor labels May 4, 2022
@AndrewKushnir AndrewKushnir added target: minor and removed target: rc labels Jun 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
comp: compiler state: blocked target: minor
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants