fix(ivy): ignore imports without ngInjectorDef in r3_injector (#24862)

ngInjectorDef.imports is generated from @NgModule.imports plus
@NgModule.exports. A problem arises as a result, because @NgModule
exports contain not only other modules (which will have ngInjectorDef
fields), but components, directives, and pipes as well. Because of
locality, it's difficult for the compiler to filter these out at
build time.

It's not impossible, but for now filtering them out at runtime will
allow testing of the compiler against complex applications.

PR Close #24862
This commit is contained in:
Alex Rickabaugh 2018-07-10 10:01:30 -07:00 committed by Victor Berchet
parent ae4563202c
commit 9644873023
2 changed files with 23 additions and 3 deletions

View File

@ -231,9 +231,9 @@ export class R3Injector {
def = ngModule.ngInjectorDef;
}
// If no definition was found, throw.
// If no definition was found, it might be from exports. Remove it.
if (def == null) {
throw new Error(`Type ${stringify(defType)} is missing an ngInjectorDef definition.`);
return;
}
// Check for circular dependencies.
@ -333,7 +333,12 @@ export class R3Injector {
function injectableDefRecord(token: Type<any>| InjectionToken<any>): Record<any> {
const def = (token as InjectableType<any>).ngInjectableDef as InjectableDef<any>;
if (def === undefined) {
throw new Error(`Type ${stringify(token)} is missing an ngInjectableDef definition.`);
if (token instanceof InjectionToken) {
throw new Error(`Token ${stringify(token)} is missing an ngInjectableDef definition.`);
}
// TODO(alxhub): there should probably be a strict mode which throws here instead of assuming a
// no-args constructor.
return makeRecord(() => new (token as Type<any>)());
}
return makeRecord(def.factory);
}

View File

@ -143,6 +143,16 @@ describe('InjectorDef-based createInjector()', () => {
});
}
class NotAModule {}
class ImportsNotAModule {
static ngInjectorDef = defineInjector({
factory: () => new ImportsNotAModule(),
imports: [NotAModule],
providers: [],
});
}
class ScopedService {
static ngInjectableDef = defineInjectable({
providedIn: Module,
@ -241,4 +251,9 @@ describe('InjectorDef-based createInjector()', () => {
expect(() => (injector as R3Injector).destroy())
.toThrowError('Injector has already been destroyed.');
});
it('should not crash when importing something that has no ngInjectorDef', () => {
injector = createInjector(ImportsNotAModule);
expect(injector.get(ImportsNotAModule)).toBeDefined();
});
});