fix(ivy): support string tokens in dependency injection (#27383)

In Angular, it used to be an accepted practice to use strings as dependency
injection tokens. E.g. {provide: 'test', useValue: 'provided'}. However,
the Ivy node injection system did not support this. The Ivy DI system
attempts to patch a Bloom bit index onto each type registered with it, and
this patch operation does not work for a string token.

This commit adds string token support to the bloom filter system by
reserving bit 0 for string tokens. This eliminates the need for each string
token to store its own Bloom bit, at the expense of slightly more expensive
lookups of string tokens.

PR Close #27383
This commit is contained in:
Alex Rickabaugh
2018-11-28 12:51:00 -08:00
committed by Igor Minar
parent c96dea27ce
commit 64a34616d8
2 changed files with 39 additions and 5 deletions

View File

@ -87,9 +87,10 @@ let nextNgElementId = 0;
* @param type The directive token to register
*/
export function bloomAdd(
injectorIndex: number, tView: TView, type: Type<any>| InjectionToken<any>): void {
injectorIndex: number, tView: TView, type: Type<any>| InjectionToken<any>| string): void {
ngDevMode && assertEqual(tView.firstTemplatePass, true, 'expected firstTemplatePass to be true');
let id: number|undefined = (type as any)[NG_ELEMENT_ID];
let id: number|undefined =
typeof type !== 'string' ? (type as any)[NG_ELEMENT_ID] : type.charCodeAt(0) || 0;
// Set a unique ID on the directive type, so if something tries to inject the directive,
// we can easily retrieve the ID and hash it into the bloom bit that should be checked.
@ -502,9 +503,12 @@ export function getNodeInjectable(
* @param token the injection token
* @returns the matching bit to check in the bloom filter or `null` if the token is not known.
*/
export function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>): number|Function|
undefined {
export function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>| string): number|
Function|undefined {
ngDevMode && assertDefined(token, 'token must be defined');
if (typeof token === 'string') {
return token.charCodeAt(0) || 0;
}
const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID];
return typeof tokenId === 'number' ? tokenId & BLOOM_MASK : tokenId;
}