diff --git a/goldens/circular-deps/packages.json b/goldens/circular-deps/packages.json index 54ddcdca4f..275a539843 100644 --- a/goldens/circular-deps/packages.json +++ b/goldens/circular-deps/packages.json @@ -255,21 +255,6 @@ "packages/core/src/render3/definition.ts", "packages/core/src/metadata/ng_module.ts" ], - [ - "packages/core/src/application_ref.ts", - "packages/core/src/application_tokens.ts", - "packages/core/src/linker/component_factory.ts", - "packages/core/src/change_detection/change_detection.ts", - "packages/core/src/change_detection/change_detector_ref.ts", - "packages/core/src/render3/view_ref.ts", - "packages/core/src/linker/view_container_ref.ts", - "packages/core/src/render3/di.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts" - ], [ "packages/core/src/application_ref.ts", "packages/core/src/application_tokens.ts", @@ -641,16 +626,6 @@ "packages/core/src/render3/definition.ts", "packages/core/src/metadata/ng_module.ts" ], - [ - "packages/core/src/application_ref.ts", - "packages/core/src/linker/compiler.ts", - "packages/core/src/render3/ng_module_ref.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts" - ], [ "packages/core/src/application_ref.ts", "packages/core/src/linker/compiler.ts", @@ -786,20 +761,6 @@ "packages/core/src/render3/definition.ts", "packages/core/src/metadata/ng_module.ts" ], - [ - "packages/core/src/application_ref.ts", - "packages/core/src/metadata/resource_loading.ts", - "packages/core/src/metadata/directives.ts", - "packages/core/src/render3/jit/directive.ts", - "packages/core/src/render3/jit/environment.ts", - "packages/core/src/render3/index.ts", - "packages/core/src/render3/pipe.ts", - "packages/core/src/di/injector_compatibility.ts", - "packages/core/src/di/injector.ts", - "packages/core/src/di/r3_injector.ts", - "packages/core/src/render3/definition.ts", - "packages/core/src/metadata/ng_module.ts" - ], [ "packages/core/src/application_ref.ts", "packages/core/src/metadata/resource_loading.ts", @@ -900,6 +861,16 @@ "packages/core/src/view/entrypoint.ts", "packages/core/src/view/services.ts" ], + [ + "packages/core/src/di.ts", + "packages/core/src/di/index.ts", + "packages/core/src/di/injectable.ts", + "packages/core/src/di/jit/injectable.ts", + "packages/core/src/di/jit/environment.ts", + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/null_injector.ts" + ], [ "packages/core/src/di/injectable.ts", "packages/core/src/di/jit/injectable.ts" @@ -908,6 +879,11 @@ "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts" ], + [ + "packages/core/src/di/injector_compatibility.ts", + "packages/core/src/di/injector.ts", + "packages/core/src/di/null_injector.ts" + ], [ "packages/core/src/di/injector_compatibility.ts", "packages/core/src/di/injector.ts", @@ -921,6 +897,10 @@ "packages/core/src/metadata/ng_module.ts", "packages/core/src/di/util.ts" ], + [ + "packages/core/src/di/injector_token.ts", + "packages/core/src/di/injector.ts" + ], [ "packages/core/src/di/injector.ts", "packages/core/src/di/r3_injector.ts" diff --git a/goldens/public-api/core/core.d.ts b/goldens/public-api/core/core.d.ts index e2a87e69cf..5a861d8adb 100644 --- a/goldens/public-api/core/core.d.ts +++ b/goldens/public-api/core/core.d.ts @@ -837,11 +837,11 @@ export declare interface RendererType2 { } export declare class ResolvedReflectiveFactory { - dependencies: ɵangular_packages_core_core_e[]; + dependencies: ɵangular_packages_core_core_d[]; factory: Function; constructor( factory: Function, - dependencies: ɵangular_packages_core_core_e[]); + dependencies: ɵangular_packages_core_core_d[]); } export declare interface ResolvedReflectiveProvider { diff --git a/goldens/size-tracking/aio-payloads.json b/goldens/size-tracking/aio-payloads.json index 716bf6c5e4..f2432d0dec 100755 --- a/goldens/size-tracking/aio-payloads.json +++ b/goldens/size-tracking/aio-payloads.json @@ -12,7 +12,7 @@ "master": { "uncompressed": { "runtime-es2015": 3037, - "main-es2015": 449483, + "main-es2015": 448796, "polyfills-es2015": 52415 } } diff --git a/goldens/size-tracking/integration-payloads.json b/goldens/size-tracking/integration-payloads.json index 292c6782b5..f00ac8b847 100644 --- a/goldens/size-tracking/integration-payloads.json +++ b/goldens/size-tracking/integration-payloads.json @@ -21,7 +21,7 @@ "master": { "uncompressed": { "runtime-es2015": 1485, - "main-es2015": 147252, + "main-es2015": 146680, "polyfills-es2015": 36964 } } diff --git a/packages/core/src/di/index.ts b/packages/core/src/di/index.ts index 1f10512092..845757d5d6 100644 --- a/packages/core/src/di/index.ts +++ b/packages/core/src/di/index.ts @@ -18,7 +18,8 @@ export {ɵɵdefineInjectable, defineInjectable, ɵɵdefineInjector, InjectableTy export {forwardRef, resolveForwardRef, ForwardRefFn} from './forward_ref'; export {Injectable, InjectableDecorator, InjectableProvider} from './injectable'; export {Injector} from './injector'; -export {ɵɵinject, inject, INJECTOR, ɵɵinvalidFactoryDep} from './injector_compatibility'; +export {ɵɵinject, inject, ɵɵinvalidFactoryDep} from './injector_compatibility'; +export {INJECTOR} from './injector_token'; export {ReflectiveInjector} from './reflective_injector'; export {ClassProvider, ClassSansProvider, ConstructorProvider, ConstructorSansProvider, ExistingProvider, ExistingSansProvider, FactoryProvider, FactorySansProvider, Provider, StaticClassProvider, StaticClassSansProvider, StaticProvider, TypeProvider, ValueProvider, ValueSansProvider} from './interface/provider'; export {ResolvedReflectiveFactory, ResolvedReflectiveProvider} from './reflective_provider'; diff --git a/packages/core/src/di/inject_switch.ts b/packages/core/src/di/inject_switch.ts new file mode 100644 index 0000000000..bc5527566e --- /dev/null +++ b/packages/core/src/di/inject_switch.ts @@ -0,0 +1,76 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {Type} from '../interface/type'; +import {assertNotEqual} from '../util/assert'; +import {stringify} from '../util/stringify'; +import {InjectionToken} from './injection_token'; +import {getInjectableDef, ɵɵInjectableDef} from './interface/defs'; +import {InjectFlags} from './interface/injector'; + + +/** + * Current implementation of inject. + * + * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed + * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this + * way for two reasons: + * 1. `Injector` should not depend on ivy logic. + * 2. To maintain tree shake-ability we don't want to bring in unnecessary code. + */ +let _injectImplementation: (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)| + undefined; +export function getInjectImplementation() { + return _injectImplementation; +} + + +/** + * Sets the current inject implementation. + */ +export function setInjectImplementation( + impl: (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)| + undefined): (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)|undefined { + const previous = _injectImplementation; + _injectImplementation = impl; + return previous; +} + + +/** + * Injects `root` tokens in limp mode. + * + * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to + * `"root"`. This is known as the limp mode injection. In such case the value is stored in the + * `InjectableDef`. + */ +export function injectRootLimpMode<T>( + token: Type<T>|InjectionToken<T>, notFoundValue: T|undefined, flags: InjectFlags): T|null { + const injectableDef: ɵɵInjectableDef<T>|null = getInjectableDef(token); + if (injectableDef && injectableDef.providedIn == 'root') { + return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() : + injectableDef.value; + } + if (flags & InjectFlags.Optional) return null; + if (notFoundValue !== undefined) return notFoundValue; + throw new Error(`Injector: NOT_FOUND [${stringify(token)}]`); +} + + +/** + * Assert that `_injectImplementation` is not `fn`. + * + * This is useful, to prevent infinite recursion. + * + * @param fn Function which it should not equal to + */ +export function assertInjectImplementationNotEqual( + fn: (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)) { + ngDevMode && + assertNotEqual(_injectImplementation, fn, 'Calling ɵɵinject would cause infinite recursion'); +} diff --git a/packages/core/src/di/injection_token.ts b/packages/core/src/di/injection_token.ts index 9abf11a849..f8b26f7eab 100644 --- a/packages/core/src/di/injection_token.ts +++ b/packages/core/src/di/injection_token.ts @@ -7,6 +7,7 @@ */ import {Type} from '../interface/type'; +import {assertLessThan} from '../util/assert'; import {ɵɵdefineInjectable} from './interface/defs'; @@ -61,9 +62,10 @@ export class InjectionToken<T> { }) { this.ɵprov = undefined; if (typeof options == 'number') { + (typeof ngDevMode === 'undefined' || ngDevMode) && + assertLessThan(options, 0, 'Only negative numbers are supported here'); // This is a special hack to assign __NG_ELEMENT_ID__ to this instance. - // __NG_ELEMENT_ID__ is Used by Ivy to determine bloom filter id. - // We are using it to assign `-1` which is used to identify `Injector`. + // See `InjectorMarkers` (this as any).__NG_ELEMENT_ID__ = options; } else if (options !== undefined) { this.ɵprov = ɵɵdefineInjectable({ diff --git a/packages/core/src/di/injector.ts b/packages/core/src/di/injector.ts index f8c93c42a0..5fda8bfbf1 100644 --- a/packages/core/src/di/injector.ts +++ b/packages/core/src/di/injector.ts @@ -8,14 +8,16 @@ import {AbstractType, Type} from '../interface/type'; import {stringify} from '../util/stringify'; - import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; -import {catchInjectorError, formatError, INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, setCurrentInjector, THROW_IF_NOT_FOUND, USE_VALUE, ɵɵinject} from './injector_compatibility'; +import {catchInjectorError, formatError, NG_TEMP_TOKEN_PATH, setCurrentInjector, THROW_IF_NOT_FOUND, USE_VALUE, ɵɵinject} from './injector_compatibility'; +import {InjectorMarkers} from './injector_marker'; +import {INJECTOR} from './injector_token'; import {getInjectableDef, ɵɵdefineInjectable} from './interface/defs'; import {InjectFlags} from './interface/injector'; import {ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, ValueProvider} from './interface/provider'; import {Inject, Optional, Self, SkipSelf} from './metadata'; +import {NullInjector} from './null_injector'; import {createInjector} from './r3_injector'; import {INJECTOR_SCOPE} from './scope'; @@ -113,7 +115,7 @@ export abstract class Injector { * @internal * @nocollapse */ - static __NG_ELEMENT_ID__ = -1; + static __NG_ELEMENT_ID__ = InjectorMarkers.Injector; } diff --git a/packages/core/src/di/injector_compatibility.ts b/packages/core/src/di/injector_compatibility.ts index fde76e1801..249ce8b992 100644 --- a/packages/core/src/di/injector_compatibility.ts +++ b/packages/core/src/di/injector_compatibility.ts @@ -14,28 +14,14 @@ import {getClosureSafeProperty} from '../util/property'; import {stringify} from '../util/stringify'; import {resolveForwardRef} from './forward_ref'; +import {getInjectImplementation, injectRootLimpMode} from './inject_switch'; import {InjectionToken} from './injection_token'; import {Injector} from './injector'; -import {getInjectableDef, ɵɵInjectableDef} from './interface/defs'; import {InjectFlags} from './interface/injector'; import {ValueProvider} from './interface/provider'; import {Inject, Optional, Self, SkipSelf} from './metadata'; - -/** - * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors. - * - * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a - * project. - * - * @publicApi - */ -export const INJECTOR = new InjectionToken<Injector>( - 'INJECTOR', - -1 as any // `-1` is used by Ivy DI system as special value to recognize it as `Injector`. -); - const _THROW_IF_NOT_FOUND = {}; export const THROW_IF_NOT_FOUND = _THROW_IF_NOT_FOUND; @@ -62,41 +48,6 @@ export function setCurrentInjector(injector: Injector|null|undefined): Injector| return former; } -/** - * Current implementation of inject. - * - * By default, it is `injectInjectorOnly`, which makes it `Injector`-only aware. It can be changed - * to `directiveInject`, which brings in the `NodeInjector` system of ivy. It is designed this - * way for two reasons: - * 1. `Injector` should not depend on ivy logic. - * 2. To maintain tree shake-ability we don't want to bring in unnecessary code. - */ -let _injectImplementation: (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)| - undefined; - -/** - * Sets the current inject implementation. - */ -export function setInjectImplementation( - impl: (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)| - undefined): (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)|undefined { - const previous = _injectImplementation; - _injectImplementation = impl; - return previous; -} - -/** - * Assert that `_injectImplementation` is not `fn`. - * - * This is useful, to prevent infinite recursion. - * - * @param fn Function which it should not equal to - */ -export function assertInjectImplementationNot( - fn: (<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags) => T | null)) { - ngDevMode && - assertNotEqual(_injectImplementation, fn, 'Calling ɵɵinject would cause infinite recursion'); -} export function injectInjectorOnly<T>(token: Type<T>|InjectionToken<T>): T; export function injectInjectorOnly<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags): T| @@ -128,7 +79,7 @@ export function injectInjectorOnly<T>( export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>): T; export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>, flags?: InjectFlags): T|null; export function ɵɵinject<T>(token: Type<T>|InjectionToken<T>, flags = InjectFlags.Default): T|null { - return (_injectImplementation || injectInjectorOnly)(resolveForwardRef(token), flags); + return (getInjectImplementation() || injectInjectorOnly)(resolveForwardRef(token), flags); } /** @@ -181,24 +132,6 @@ Please check that 1) the type for the parameter at index ${ */ export const inject = ɵɵinject; -/** - * Injects `root` tokens in limp mode. - * - * If no injector exists, we can still inject tree-shakable providers which have `providedIn` set to - * `"root"`. This is known as the limp mode injection. In such case the value is stored in the - * `InjectableDef`. - */ -export function injectRootLimpMode<T>( - token: Type<T>|InjectionToken<T>, notFoundValue: T|undefined, flags: InjectFlags): T|null { - const injectableDef: ɵɵInjectableDef<T>|null = getInjectableDef(token); - if (injectableDef && injectableDef.providedIn == 'root') { - return injectableDef.value === undefined ? injectableDef.value = injectableDef.factory() : - injectableDef.value; - } - if (flags & InjectFlags.Optional) return null; - if (notFoundValue !== undefined) return notFoundValue; - throw new Error(`Injector: NOT_FOUND [${stringify(token)}]`); -} export function injectArgs(types: (Type<any>|InjectionToken<any>|any[])[]): any[] { const args: any[] = []; @@ -236,22 +169,6 @@ export function injectArgs(types: (Type<any>|InjectionToken<any>|any[])[]): any[ } -export class NullInjector implements Injector { - get(token: any, notFoundValue: any = THROW_IF_NOT_FOUND): any { - if (notFoundValue === THROW_IF_NOT_FOUND) { - // Intentionally left behind: With dev tools open the debugger will stop here. There is no - // reason why correctly written application should cause this exception. - // TODO(misko): uncomment the next line once `ngDevMode` works with closure. - // if (ngDevMode) debugger; - const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`); - error.name = 'NullInjectorError'; - throw error; - } - return notFoundValue; - } -} - - export function catchInjectorError( e: any, token: any, injectorErrorName: string, source: string|null): never { const tokenPath: any[] = e[NG_TEMP_TOKEN_PATH]; diff --git a/packages/core/src/di/injector_marker.ts b/packages/core/src/di/injector_marker.ts new file mode 100644 index 0000000000..ff13f93b72 --- /dev/null +++ b/packages/core/src/di/injector_marker.ts @@ -0,0 +1,24 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * Special markers which can be left on `Type.__NG_ELEMENT_ID__` which are used by the Ivy's + * `NodeInjector`. Usually these markers contain factory functions. But in case of this special + * marker we can't leave behind a function because it would create tree shaking problem. + * + * Currently only `Injector` is special. + * + * NOTE: the numbers here must be negative, because positive numbers are used as IDs for bloom + * filter. + */ +export const enum InjectorMarkers { + /** + * Marks that the current type is `Injector` + */ + Injector = -1 +} \ No newline at end of file diff --git a/packages/core/src/di/injector_token.ts b/packages/core/src/di/injector_token.ts new file mode 100644 index 0000000000..b84fc4a261 --- /dev/null +++ b/packages/core/src/di/injector_token.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {InjectionToken} from './injection_token'; +import {Injector} from './injector'; +import {InjectorMarkers} from './injector_marker'; + + + +/** + * An InjectionToken that gets the current `Injector` for `createInjector()`-style injectors. + * + * Requesting this token instead of `Injector` allows `StaticInjector` to be tree-shaken from a + * project. + * + * @publicApi + */ +export const INJECTOR = new InjectionToken<Injector>( + 'INJECTOR', + // Dissable tslint because this is const enum which gets inlined not top level prop access. + // tslint:disable-next-line: no-toplevel-property-access + InjectorMarkers.Injector as any, // Special value used by Ivy to identify `Injector`. +); diff --git a/packages/core/src/di/null_injector.ts b/packages/core/src/di/null_injector.ts new file mode 100644 index 0000000000..fb889c92c9 --- /dev/null +++ b/packages/core/src/di/null_injector.ts @@ -0,0 +1,23 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {stringify} from '../util/stringify'; +import {Injector} from '.'; +import {THROW_IF_NOT_FOUND} from './injector_compatibility'; + + +export class NullInjector implements Injector { + get(token: any, notFoundValue: any = THROW_IF_NOT_FOUND): any { + if (notFoundValue === THROW_IF_NOT_FOUND) { + const error = new Error(`NullInjectorError: No provider for ${stringify(token)}!`); + error.name = 'NullInjectorError'; + throw error; + } + return notFoundValue; + } +} diff --git a/packages/core/src/di/r3_injector.ts b/packages/core/src/di/r3_injector.ts index 1c147e622e..53823799d6 100644 --- a/packages/core/src/di/r3_injector.ts +++ b/packages/core/src/di/r3_injector.ts @@ -19,10 +19,12 @@ import {stringify} from '../util/stringify'; import {resolveForwardRef} from './forward_ref'; import {InjectionToken} from './injection_token'; import {Injector} from './injector'; -import {catchInjectorError, injectArgs, INJECTOR, NG_TEMP_TOKEN_PATH, NullInjector, setCurrentInjector, THROW_IF_NOT_FOUND, USE_VALUE, ɵɵinject} from './injector_compatibility'; +import {catchInjectorError, injectArgs, NG_TEMP_TOKEN_PATH, setCurrentInjector, THROW_IF_NOT_FOUND, USE_VALUE, ɵɵinject} from './injector_compatibility'; +import {INJECTOR} from './injector_token'; import {getInheritedInjectableDef, getInjectableDef, getInjectorDef, InjectorType, InjectorTypeWithProviders, ɵɵInjectableDef} from './interface/defs'; import {InjectFlags} from './interface/injector'; import {ClassProvider, ConstructorProvider, ExistingProvider, FactoryProvider, StaticClassProvider, StaticProvider, TypeProvider, ValueProvider} from './interface/provider'; +import {NullInjector} from './null_injector'; import {INJECTOR_SCOPE} from './scope'; diff --git a/packages/core/src/render3/di.ts b/packages/core/src/render3/di.ts index 5e0fc857df..5f4fd9054a 100644 --- a/packages/core/src/render3/di.ts +++ b/packages/core/src/render3/di.ts @@ -7,9 +7,10 @@ */ import {isForwardRef, resolveForwardRef} from '../di/forward_ref'; +import {injectRootLimpMode, setInjectImplementation} from '../di/inject_switch'; import {InjectionToken} from '../di/injection_token'; import {Injector} from '../di/injector'; -import {injectRootLimpMode, setInjectImplementation} from '../di/injector_compatibility'; +import {InjectorMarkers} from '../di/injector_marker'; import {getInjectorDef} from '../di/interface/defs'; import {InjectFlags} from '../di/interface/injector'; import {Type} from '../interface/type'; @@ -415,8 +416,11 @@ export function getOrCreateInjectable<T>( // so just call the factory function to create it. if (typeof bloomHash === 'function') { if (!enterDI(lView, tNode, flags)) { - // Failed to enter DI use module injector instead. - return lookupTokenUsingModuleInjector<T>(lView, token, flags, notFoundValue); + // Failed to enter DI, try module injector instead. If a token is injected with the @Host + // flag, the module injector is not searched for that token in Ivy. + return (flags & InjectFlags.Host) ? + notFoundValueOrThrow<T>(notFoundValue, token, flags) : + lookupTokenUsingModuleInjector<T>(lView, token, flags, notFoundValue); } try { const value = bloomHash(); @@ -429,32 +433,6 @@ export function getOrCreateInjectable<T>( leaveDI(); } } else if (typeof bloomHash === 'number') { - // This is a value used to identify __NG_ELEMENT_ID__ - // `-1` is a special value used to identify `Injector` types in NodeInjector - // This is a workaround for the fact that if the `Injector.__NG_ELEMENT_ID__` - // would have a factory function (such as `ElementRef`) it would cause Ivy - // to be pulled into the ViewEngine, because they both share `Injector` type. - // This should be refactored to follow `ElementRef` pattern once ViewEngine is - // removed - if (bloomHash === -1) { - if (!enterDI(lView, tNode, flags)) { - // Failed to enter DI, try module injector instead. If a token is injected with the @Host - // flag, the module injector is not searched for that token in Ivy. - return (flags & InjectFlags.Host) ? - notFoundValueOrThrow<T>(notFoundValue, token, flags) : - lookupTokenUsingModuleInjector<T>(lView, token, flags, notFoundValue); - } - try { - // Retrieving current `TNode` and `LView` from the state (rather than using `tNode` and - // `lView`), because entering DI (by calling `enterDI`) may cause these values to change - // (in case `@SkipSelf` flag is present). - return new NodeInjector(getCurrentTNode()! as TDirectiveHostNode, getLView()) as any; - } finally { - leaveDI(); - } - } - // If the token has a bloom hash, then it is a token which could be in NodeInjector. - // A reference to the previous injector TView that was found while climbing the element // injector tree. This is used to know if viewProviders can be accessed on the current // injector. @@ -525,6 +503,10 @@ export function getOrCreateInjectable<T>( const NOT_FOUND = {}; +export function createNodeInjector(): Injector { + return new NodeInjector(getCurrentTNode()! as TDirectiveHostNode, getLView()) as any; +} + function searchTokensOnInjector<T>( injectorIndex: number, lView: LView, token: Type<T>|InjectionToken<T>, previousTView: TView|null, flags: InjectFlags, hostTElementNode: TNode|null) { @@ -674,7 +656,17 @@ export function bloomHashBitOrFactory(token: Type<any>|InjectionToken<any>|strin // First check with `hasOwnProperty` so we don't get an inherited ID. token.hasOwnProperty(NG_ELEMENT_ID) ? (token as any)[NG_ELEMENT_ID] : undefined; // Negative token IDs are used for special objects such as `Injector` - return (typeof tokenId === 'number' && tokenId > 0) ? tokenId & BLOOM_MASK : tokenId; + if (typeof tokenId === 'number') { + if (tokenId >= 0) { + return tokenId & BLOOM_MASK; + } else { + ngDevMode && + assertEqual(tokenId, InjectorMarkers.Injector, 'Expecting to get Special Injector Id'); + return createNodeInjector; + } + } else { + return tokenId; + } } export function bloomHasToken(bloomHash: number, injectorIndex: number, injectorView: LView|TData) { diff --git a/packages/core/src/render3/instructions/di.ts b/packages/core/src/render3/instructions/di.ts index 1868e1868c..bb08814e5a 100644 --- a/packages/core/src/render3/instructions/di.ts +++ b/packages/core/src/render3/instructions/di.ts @@ -6,7 +6,8 @@ * found in the LICENSE file at https://angular.io/license */ import {InjectFlags, InjectionToken, resolveForwardRef} from '../../di'; -import {assertInjectImplementationNot, ɵɵinject} from '../../di/injector_compatibility'; +import {assertInjectImplementationNotEqual} from '../../di/inject_switch'; +import {ɵɵinject} from '../../di/injector_compatibility'; import {Type} from '../../interface/type'; import {getOrCreateInjectable, injectAttributeImpl} from '../di'; import {TDirectiveHostNode} from '../interfaces/node'; @@ -45,7 +46,7 @@ export function ɵɵdirectiveInject<T>( // if inject utilities are used before bootstrapping. if (lView === null) { // Verify that we will not get into infinite loop. - ngDevMode && assertInjectImplementationNot(ɵɵdirectiveInject); + ngDevMode && assertInjectImplementationNotEqual(ɵɵdirectiveInject); return ɵɵinject(token, flags); } const tNode = getCurrentTNode(); diff --git a/packages/core/src/render3/ng_module_ref.ts b/packages/core/src/render3/ng_module_ref.ts index 4cb7227c6f..a388e68aa8 100644 --- a/packages/core/src/render3/ng_module_ref.ts +++ b/packages/core/src/render3/ng_module_ref.ts @@ -7,7 +7,7 @@ */ import {Injector} from '../di/injector'; -import {INJECTOR} from '../di/injector_compatibility'; +import {INJECTOR} from '../di/injector_token'; import {InjectFlags} from '../di/interface/injector'; import {createInjectorWithoutInjectorInstances, R3Injector} from '../di/r3_injector'; import {Type} from '../interface/type'; diff --git a/packages/core/src/render3/pipe.ts b/packages/core/src/render3/pipe.ts index e9fb78a1ae..148e795184 100644 --- a/packages/core/src/render3/pipe.ts +++ b/packages/core/src/render3/pipe.ts @@ -8,8 +8,7 @@ import {WrappedValue} from '../change_detection/change_detection_util'; import {PipeTransform} from '../change_detection/pipe_transform'; -import {setInjectImplementation} from '../di/injector_compatibility'; - +import {setInjectImplementation} from '../di/inject_switch'; import {getFactoryDef} from './definition'; import {setIncludeViewProviders} from './di'; import {RuntimeError, RuntimeErrorCode} from './error_code'; diff --git a/packages/core/src/view/ng_module.ts b/packages/core/src/view/ng_module.ts index ac46b4921e..5a414d4548 100644 --- a/packages/core/src/view/ng_module.ts +++ b/packages/core/src/view/ng_module.ts @@ -8,7 +8,8 @@ import {resolveForwardRef} from '../di/forward_ref'; import {Injector} from '../di/injector'; -import {INJECTOR, setCurrentInjector} from '../di/injector_compatibility'; +import {setCurrentInjector} from '../di/injector_compatibility'; +import {INJECTOR} from '../di/injector_token'; import {getInjectableDef, ɵɵInjectableDef} from '../di/interface/defs'; import {INJECTOR_SCOPE} from '../di/scope'; import {NgModuleRef} from '../linker/ng_module_factory'; diff --git a/packages/core/test/bundling/forms/bundle.golden_symbols.json b/packages/core/test/bundling/forms/bundle.golden_symbols.json index 6325a87e2c..14d53f82a3 100644 --- a/packages/core/test/bundling/forms/bundle.golden_symbols.json +++ b/packages/core/test/bundling/forms/bundle.golden_symbols.json @@ -833,6 +833,9 @@ { "name": "createLView" }, + { + "name": "createNodeInjector" + }, { "name": "createPlatformFactory" }, diff --git a/packages/core/test/bundling/router/bundle.golden_symbols.json b/packages/core/test/bundling/router/bundle.golden_symbols.json index c00bdbf7b8..0f0af28545 100644 --- a/packages/core/test/bundling/router/bundle.golden_symbols.json +++ b/packages/core/test/bundling/router/bundle.golden_symbols.json @@ -1073,6 +1073,9 @@ { "name": "createNewSegmentGroup" }, + { + "name": "createNodeInjector" + }, { "name": "createPlatformFactory" }, diff --git a/packages/core/test/bundling/todo/bundle.golden_symbols.json b/packages/core/test/bundling/todo/bundle.golden_symbols.json index ada284be31..64b81583e2 100644 --- a/packages/core/test/bundling/todo/bundle.golden_symbols.json +++ b/packages/core/test/bundling/todo/bundle.golden_symbols.json @@ -272,6 +272,9 @@ { "name": "createLView" }, + { + "name": "createNodeInjector" + }, { "name": "createTView" }, diff --git a/packages/core/test/view/ng_module_spec.ts b/packages/core/test/view/ng_module_spec.ts index a139047e8a..937568cfb6 100644 --- a/packages/core/test/view/ng_module_spec.ts +++ b/packages/core/test/view/ng_module_spec.ts @@ -9,7 +9,7 @@ import {NgModuleRef, ɵINJECTOR_SCOPE as INJECTOR_SCOPE} from '@angular/core'; import {inject, InjectFlags} from '@angular/core/src/di'; import {Injector} from '@angular/core/src/di/injector'; -import {INJECTOR} from '@angular/core/src/di/injector_compatibility'; +import {INJECTOR} from '@angular/core/src/di/injector_token'; import {ɵɵdefineInjectable, ɵɵInjectableDef} from '@angular/core/src/di/interface/defs'; import {NgModuleDefinition, NgModuleProviderDef, NodeFlags} from '@angular/core/src/view'; import {moduleDef} from '@angular/core/src/view/ng_module';