feat(ivy): error in ivy when inheriting a ctor from an undecorated base (#34460)
Angular View Engine uses global knowledge to compile the following code: ```typescript export class Base { constructor(private vcr: ViewContainerRef) {} } @Directive({...}) export class Dir extends Base { // constructor inherited from base } ``` Here, `Dir` extends `Base` and inherits its constructor. To create a `Dir` the arguments to this inherited constructor must be obtained via dependency injection. View Engine is able to generate a correct factory for `Dir` to do this because via metadata it knows the arguments of `Base`'s constructor, even if `Base` is declared in a different library. In Ivy, DI is entirely a runtime concept. Currently `Dir` is compiled with an ngDirectiveDef field that delegates its factory to `getInheritedFactory`. This looks for some kind of factory function on `Base`, which comes up empty. This case looks identical to an inheritance chain with no constructors, which works today in Ivy. Both of these cases will now become an error in this commit. If a decorated class inherits from an undecorated base class, a diagnostic is produced informing the user of the need to either explicitly declare a constructor or to decorate the base class. PR Close #34460
This commit is contained in:
@ -100,7 +100,7 @@ export class DecorationAnalyzer {
|
||||
// clang-format off
|
||||
new DirectiveDecoratorHandler(
|
||||
this.reflectionHost, this.evaluator, this.fullRegistry, this.scopeRegistry,
|
||||
NOOP_DEFAULT_IMPORT_RECORDER, this.injectableRegistry, this.isCore,
|
||||
this.fullMetaReader, NOOP_DEFAULT_IMPORT_RECORDER, this.injectableRegistry, this.isCore,
|
||||
/* annotateForClosureCompiler */ false) as DecoratorHandler<unknown, unknown, unknown>,
|
||||
// clang-format on
|
||||
// Pipe handler must be before injectable handler in list so pipe factories are printed
|
||||
|
@ -207,7 +207,7 @@ runInEachFileSystem(() => {
|
||||
|
||||
it('should skip the base class if it is in a different package from the derived class', () => {
|
||||
const BASE_FILENAME = _('/node_modules/other-package/index.js');
|
||||
const {program, analysis, errors} = setUpAndAnalyzeProgram([
|
||||
const {errors} = setUpAndAnalyzeProgram([
|
||||
{
|
||||
name: INDEX_FILENAME,
|
||||
contents: `
|
||||
@ -232,9 +232,16 @@ runInEachFileSystem(() => {
|
||||
`
|
||||
}
|
||||
]);
|
||||
expect(errors).toEqual([]);
|
||||
const file = analysis.get(program.getSourceFile(BASE_FILENAME) !);
|
||||
expect(file).toBeUndefined();
|
||||
|
||||
expect(errors.length).toBe(1);
|
||||
expect(errors[0].messageText)
|
||||
.toBe(
|
||||
`The directive DerivedClass inherits its constructor ` +
|
||||
`from BaseClass, but the latter does not have an Angular ` +
|
||||
`decorator of its own. Dependency injection will not be ` +
|
||||
`able to resolve the parameters of BaseClass's ` +
|
||||
`constructor. Either add a @Directive decorator to ` +
|
||||
`BaseClass, or add an explicit constructor to DerivedClass.`);
|
||||
});
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user