refactor(ivy): remove reserveSlots instruction (#25533)

PR Close #25533
This commit is contained in:
Kara Erickson 2018-08-15 16:32:08 -07:00 committed by Jason Aden
parent 21d22ce4ad
commit 4708cb91ef
8 changed files with 281 additions and 295 deletions

View File

@ -7,7 +7,7 @@
*/
import {assertEqual, assertLessThan} from './assert';
import {NO_CHANGE, _getViewData, bindingUpdated, bindingUpdated2, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, load, resetApplicationState} from './instructions';
import {NO_CHANGE, _getViewData, bindingUpdated, bindingUpdated2, bindingUpdated3, bindingUpdated4, createLNode, getPreviousOrParentNode, getRenderer, initBindings, load, resetApplicationState} from './instructions';
import {RENDER_PARENT} from './interfaces/container';
import {LContainerNode, LNode, TContainerNode, TElementNode, TNodeType} from './interfaces/node';
import {BINDING_INDEX, HEADER_OFFSET, TVIEW} from './interfaces/view';
@ -383,7 +383,8 @@ export function i18nExpMapping(
* @returns The concatenated string when any of the arguments changes, `NO_CHANGE` otherwise.
*/
export function i18nInterpolation1(instructions: I18nExpInstruction[], v0: any): string|NO_CHANGE {
const different = bindingUpdated(v0);
initBindings();
const different = bindingUpdated(_getViewData()[BINDING_INDEX]++, v0);
if (!different) {
return NO_CHANGE;
@ -414,7 +415,10 @@ export function i18nInterpolation1(instructions: I18nExpInstruction[], v0: any):
*/
export function i18nInterpolation2(instructions: I18nExpInstruction[], v0: any, v1: any): string|
NO_CHANGE {
const different = bindingUpdated2(v0, v1);
initBindings();
const viewData = _getViewData();
const different = bindingUpdated2(viewData[BINDING_INDEX], v0, v1);
viewData[BINDING_INDEX] += 2;
if (!different) {
return NO_CHANGE;
@ -452,8 +456,10 @@ export function i18nInterpolation2(instructions: I18nExpInstruction[], v0: any,
*/
export function i18nInterpolation3(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any): string|NO_CHANGE {
let different = bindingUpdated2(v0, v1);
different = bindingUpdated(v2) || different;
initBindings();
const viewData = _getViewData();
const different = bindingUpdated3(viewData[BINDING_INDEX], v0, v1, v2);
viewData[BINDING_INDEX] += 3;
if (!different) {
return NO_CHANGE;
@ -493,7 +499,10 @@ export function i18nInterpolation3(
*/
export function i18nInterpolation4(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any): string|NO_CHANGE {
const different = bindingUpdated4(v0, v1, v2, v3);
initBindings();
const viewData = _getViewData();
const different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
viewData[BINDING_INDEX] += 4;
if (!different) {
return NO_CHANGE;
@ -535,8 +544,11 @@ export function i18nInterpolation4(
export function i18nInterpolation5(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any): string|
NO_CHANGE {
let different = bindingUpdated4(v0, v1, v2, v3);
different = bindingUpdated(v4) || different;
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated(viewData[BINDING_INDEX] + 4, v4) || different;
viewData[BINDING_INDEX] += 5;
if (!different) {
return NO_CHANGE;
@ -580,8 +592,11 @@ export function i18nInterpolation5(
i18nInterpolation6(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any):
string|NO_CHANGE {
let different = bindingUpdated4(v0, v1, v2, v3);
different = bindingUpdated2(v4, v5) || different;
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated2(viewData[BINDING_INDEX] + 4, v4, v5) || different;
viewData[BINDING_INDEX] += 6;
if (!different) {
return NO_CHANGE;
@ -626,9 +641,11 @@ i18nInterpolation6(
export function i18nInterpolation7(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any,
v6: any): string|NO_CHANGE {
let different = bindingUpdated4(v0, v1, v2, v3);
different = bindingUpdated2(v4, v5) || different;
different = bindingUpdated(v6) || different;
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated3(viewData[BINDING_INDEX] + 4, v4, v5, v6) || different;
viewData[BINDING_INDEX] += 7;
if (!different) {
return NO_CHANGE;
@ -674,8 +691,11 @@ export function i18nInterpolation7(
export function i18nInterpolation8(
instructions: I18nExpInstruction[], v0: any, v1: any, v2: any, v3: any, v4: any, v5: any,
v6: any, v7: any): string|NO_CHANGE {
let different = bindingUpdated4(v0, v1, v2, v3);
different = bindingUpdated4(v4, v5, v6, v7) || different;
initBindings();
const viewData = _getViewData();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated4(viewData[BINDING_INDEX] + 4, v4, v5, v6, v7) || different;
viewData[BINDING_INDEX] += 8;
if (!different) {
return NO_CHANGE;
@ -713,10 +733,12 @@ export function i18nInterpolation8(
*/
export function i18nInterpolationV(instructions: I18nExpInstruction[], values: any[]): string|
NO_CHANGE {
initBindings();
const viewData = _getViewData();
let different = false;
for (let i = 0; i < values.length; i++) {
// Check if bindings have changed
bindingUpdated(values[i]) && (different = true);
bindingUpdated(viewData[BINDING_INDEX]++, values[i]) && (different = true);
}
if (!different) {

View File

@ -369,6 +369,7 @@ export function executeInitAndContentHooks(): void {
export function createLViewData<T>(
renderer: Renderer3, tView: TView, context: T | null, flags: LViewFlags,
sanitizer?: Sanitizer | null): LViewData {
// TODO(kara): create from blueprint
return [
tView, // tView
viewData, // parent
@ -2506,14 +2507,14 @@ export const NO_CHANGE = {} as NO_CHANGE;
* This function must be called before any binding related function is called
* (ie `bind()`, `interpolationX()`, `pureFunctionX()`)
*/
function initBindings() {
ngDevMode && assertEqual(
viewData[BINDING_INDEX], -1,
'Binding index should not yet be set ' + viewData[BINDING_INDEX]);
export function initBindings() {
// TODO(kara): remove this check when we have pre-filled array
if (tView.bindingStartIndex === -1) {
tView.bindingStartIndex = viewData.length;
}
viewData[BINDING_INDEX] = tView.bindingStartIndex;
if (viewData[BINDING_INDEX] === -1) {
viewData[BINDING_INDEX] = tView.bindingStartIndex;
}
}
/**
@ -2522,26 +2523,11 @@ function initBindings() {
* @param value Value to diff
*/
export function bind<T>(value: T): T|NO_CHANGE {
return bindingUpdated(value) ? value : NO_CHANGE;
initBindings();
return bindingUpdated(viewData[BINDING_INDEX]++, value) ? value : NO_CHANGE;
}
/**
* Reserves slots for pure functions (`pureFunctionX` instructions)
*
* Bindings for pure functions are stored after the LNodes in the data array but before the binding.
*
* ----------------------------------------------------------------------------
* | LNodes ... | pure function bindings | regular bindings / interpolations |
* ----------------------------------------------------------------------------
* ^
* TView.bindingStartIndex
*
* Pure function instructions are given an offset from TView.bindingStartIndex.
* Subtracting the offset from TView.bindingStartIndex gives the first index where the bindings
* are stored.
*
* NOTE: reserveSlots instructions are only ever allowed at the very end of the creation block
*/
// TODO(kara): Remove this when updating the compiler (cannot remove without breaking JIT test)
export function reserveSlots(numSlots: number) {
// Init the slots with a unique `NO_CHANGE` value so that the first change is always detected
// whether it happens or not during the first change detection pass - pure functions checks
@ -2553,29 +2539,6 @@ export function reserveSlots(numSlots: number) {
initBindings();
}
/**
* Sets up the binding index before executing any `pureFunctionX` instructions.
*
* The index must be restored after the pure function is executed
*
* {@link reserveSlots}
*/
export function moveBindingIndexToReservedSlot(offset: number): number {
const currentSlot = viewData[BINDING_INDEX];
viewData[BINDING_INDEX] = tView.bindingStartIndex - offset;
return currentSlot;
}
/**
* Restores the binding index to the given value.
*
* This function is typically used to restore the index after a `pureFunctionX` has
* been executed.
*/
export function restoreBindingIndex(index: number): void {
viewData[BINDING_INDEX] = index;
}
/**
* Create interpolation bindings with a variable number of expressions.
*
@ -2591,12 +2554,12 @@ export function restoreBindingIndex(index: number): void {
export function interpolationV(values: any[]): string|NO_CHANGE {
ngDevMode && assertLessThan(2, values.length, 'should have at least 3 values');
ngDevMode && assertEqual(values.length % 2, 1, 'should have an odd number of values');
initBindings();
let different = false;
for (let i = 1; i < values.length; i += 2) {
// Check if bindings (odd indexes) have changed
bindingUpdated(values[i]) && (different = true);
bindingUpdated(viewData[BINDING_INDEX]++, values[i]) && (different = true);
}
if (!different) {
@ -2620,15 +2583,17 @@ export function interpolationV(values: any[]): string|NO_CHANGE {
* @param suffix static value used for concatenation only.
*/
export function interpolation1(prefix: string, v0: any, suffix: string): string|NO_CHANGE {
const different = bindingUpdated(v0);
initBindings();
const different = bindingUpdated(viewData[BINDING_INDEX]++, v0);
return different ? prefix + stringify(v0) + suffix : NO_CHANGE;
}
/** Creates an interpolation binding with 2 expressions. */
export function interpolation2(
prefix: string, v0: any, i0: string, v1: any, suffix: string): string|NO_CHANGE {
const different = bindingUpdated2(v0, v1);
initBindings();
const different = bindingUpdated2(viewData[BINDING_INDEX], v0, v1);
viewData[BINDING_INDEX] += 2;
return different ? prefix + stringify(v0) + i0 + stringify(v1) + suffix : NO_CHANGE;
}
@ -2637,8 +2602,9 @@ export function interpolation2(
export function interpolation3(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, suffix: string): string|
NO_CHANGE {
let different = bindingUpdated2(v0, v1);
different = bindingUpdated(v2) || different;
initBindings();
const different = bindingUpdated3(viewData[BINDING_INDEX], v0, v1, v2);
viewData[BINDING_INDEX] += 3;
return different ? prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + suffix :
NO_CHANGE;
@ -2648,7 +2614,9 @@ export function interpolation3(
export function interpolation4(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
suffix: string): string|NO_CHANGE {
const different = bindingUpdated4(v0, v1, v2, v3);
initBindings();
const different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
viewData[BINDING_INDEX] += 4;
return different ?
prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) +
@ -2660,8 +2628,10 @@ export function interpolation4(
export function interpolation5(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, suffix: string): string|NO_CHANGE {
let different = bindingUpdated4(v0, v1, v2, v3);
different = bindingUpdated(v4) || different;
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated(viewData[BINDING_INDEX] + 4, v4) || different;
viewData[BINDING_INDEX] += 5;
return different ?
prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 +
@ -2673,8 +2643,10 @@ export function interpolation5(
export function interpolation6(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, i4: string, v5: any, suffix: string): string|NO_CHANGE {
let different = bindingUpdated4(v0, v1, v2, v3);
different = bindingUpdated2(v4, v5) || different;
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated2(viewData[BINDING_INDEX] + 4, v4, v5) || different;
viewData[BINDING_INDEX] += 6;
return different ?
prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 +
@ -2687,9 +2659,10 @@ export function interpolation7(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, suffix: string): string|
NO_CHANGE {
let different = bindingUpdated4(v0, v1, v2, v3);
different = bindingUpdated2(v4, v5) || different;
different = bindingUpdated(v6) || different;
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated3(viewData[BINDING_INDEX] + 4, v4, v5, v6) || different;
viewData[BINDING_INDEX] += 7;
return different ?
prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 +
@ -2702,8 +2675,10 @@ export function interpolation8(
prefix: string, v0: any, i0: string, v1: any, i1: string, v2: any, i2: string, v3: any,
i3: string, v4: any, i4: string, v5: any, i5: string, v6: any, i6: string, v7: any,
suffix: string): string|NO_CHANGE {
let different = bindingUpdated4(v0, v1, v2, v3);
different = bindingUpdated4(v4, v5, v6, v7) || different;
initBindings();
let different = bindingUpdated4(viewData[BINDING_INDEX], v0, v1, v2, v3);
different = bindingUpdated4(viewData[BINDING_INDEX] + 4, v4, v5, v6, v7) || different;
viewData[BINDING_INDEX] += 8;
return different ?
prefix + stringify(v0) + i0 + stringify(v1) + i1 + stringify(v2) + i2 + stringify(v3) + i3 +
@ -2770,49 +2745,51 @@ export function loadElement(index: number): LElementNode {
return loadElementInternal(index, viewData);
}
/** Gets the current binding value and increments the binding index. */
export function consumeBinding(): any {
ngDevMode && assertDataInRange(viewData[BINDING_INDEX]);
/** Gets the current binding value. */
export function getBinding(bindingIndex: number): any {
ngDevMode && assertDataInRange(viewData[bindingIndex]);
ngDevMode &&
assertNotEqual(
viewData[viewData[BINDING_INDEX]], NO_CHANGE, 'Stored value should never be NO_CHANGE.');
return viewData[viewData[BINDING_INDEX]++];
assertNotEqual(viewData[bindingIndex], NO_CHANGE, 'Stored value should never be NO_CHANGE.');
return viewData[bindingIndex];
}
/** Updates binding if changed, then returns whether it was updated. */
export function bindingUpdated(value: any): boolean {
export function bindingUpdated(bindingIndex: number, value: any): boolean {
ngDevMode && assertNotEqual(value, NO_CHANGE, 'Incoming value should never be NO_CHANGE.');
if (viewData[BINDING_INDEX] === -1) initBindings();
const bindingIndex = viewData[BINDING_INDEX];
if (bindingIndex >= viewData.length) {
viewData[viewData[BINDING_INDEX]++] = value;
viewData[bindingIndex] = value;
} else if (isDifferent(viewData[bindingIndex], value, checkNoChangesMode)) {
throwErrorIfNoChangesMode(creationMode, checkNoChangesMode, viewData[bindingIndex], value);
viewData[viewData[BINDING_INDEX]++] = value;
viewData[bindingIndex] = value;
} else {
viewData[BINDING_INDEX]++;
return false;
}
return true;
}
/** Updates binding if changed, then returns the latest value. */
export function checkAndUpdateBinding(value: any): any {
bindingUpdated(value);
return value;
/** Updates binding and returns the value. */
export function updateBinding(bindingIndex: number, value: any): any {
return viewData[bindingIndex] = value;
}
/** Updates 2 bindings if changed, then returns whether either was updated. */
export function bindingUpdated2(exp1: any, exp2: any): boolean {
const different = bindingUpdated(exp1);
return bindingUpdated(exp2) || different;
export function bindingUpdated2(bindingIndex: number, exp1: any, exp2: any): boolean {
const different = bindingUpdated(bindingIndex, exp1);
return bindingUpdated(bindingIndex + 1, exp2) || different;
}
/** Updates 3 bindings if changed, then returns whether any was updated. */
export function bindingUpdated3(bindingIndex: number, exp1: any, exp2: any, exp3: any): boolean {
const different = bindingUpdated2(bindingIndex, exp1, exp2);
return bindingUpdated(bindingIndex + 2, exp3) || different;
}
/** Updates 4 bindings if changed, then returns whether any was updated. */
export function bindingUpdated4(exp1: any, exp2: any, exp3: any, exp4: any): boolean {
const different = bindingUpdated2(exp1, exp2);
return bindingUpdated2(exp3, exp4) || different;
export function bindingUpdated4(
bindingIndex: number, exp1: any, exp2: any, exp3: any, exp4: any): boolean {
const different = bindingUpdated2(bindingIndex, exp1, exp2);
return bindingUpdated2(bindingIndex + 2, exp3, exp4) || different;
}
export function getTView(): TView {
@ -2856,22 +2833,6 @@ function assertDataNext(index: number, arr?: any[]) {
arr.length, index, `index ${index} expected to be at the end of arr (length ${arr.length})`);
}
/**
* On the first template pass, the reserved slots should be set `NO_CHANGE`.
*
* If not, they might not have been actually reserved.
*/
export function assertReservedSlotInitialized(slotOffset: number, numSlots: number) {
if (firstTemplatePass) {
const startIndex = tView.bindingStartIndex - slotOffset;
for (let i = 0; i < numSlots; i++) {
assertEqual(
viewData[startIndex + i], NO_CHANGE,
'The reserved slots should be set to `NO_CHANGE` on first template pass');
}
}
}
export function _getComponentHostLElementNode<T>(component: T): LElementNode {
ngDevMode && assertDefined(component, 'expecting component got null');
const lElementNode = (component as any)[NG_HOST_SYMBOL] as LElementNode;

View File

@ -6,34 +6,44 @@
* found in the LICENSE file at https://angular.io/license
*/
import {assertReservedSlotInitialized, bindingUpdated, bindingUpdated2, bindingUpdated4, checkAndUpdateBinding, consumeBinding, getCreationMode, moveBindingIndexToReservedSlot, restoreBindingIndex} from './instructions';
import {bindingUpdated, bindingUpdated2, bindingUpdated4, updateBinding, getBinding, getCreationMode, getTView, initBindings, bindingUpdated3,} from './instructions';
/**
* Bindings for pure functions are stored after regular bindings.
*
* ----------------------------------------------------------------------------
* | LNodes ... | regular bindings / interpolations | pure function bindings
* ----------------------------------------------------------------------------
* ^
* TView.bindingStartIndex
*
* Pure function instructions are given an offset from TView.bindingStartIndex.
* Adding the offset to TView.bindingStartIndex gives the first index where the bindings
* are stored.
*/
/**
* If the value hasn't been saved, calls the pure function to store and return the
* value. If it has been saved, returns the saved value.
*
* @param slotOffset the offset from binding root to the reserved slot
* @param pureFn Function that returns a value
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
* @param thisArg Optional calling context of pureFn
* @returns value
*/
export function pureFunction0<T>(slotOffset: number, pureFn: () => T, thisArg?: any): T {
ngDevMode && assertReservedSlotInitialized(slotOffset, 1);
const index = moveBindingIndexToReservedSlot(slotOffset);
const value = getCreationMode() ?
checkAndUpdateBinding(thisArg ? pureFn.call(thisArg) : pureFn()) :
consumeBinding();
restoreBindingIndex(index);
return value;
initBindings(); // TODO(kara): remove this check when we have pre-filled array
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return getCreationMode() ?
updateBinding(bindingIndex, thisArg ? pureFn.call(thisArg) : pureFn()) :
getBinding(bindingIndex);
}
/**
* If the value of the provided exp has changed, calls the pure function to return
* an updated value. Or if the value has not changed, returns cached value.
*
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
* @param slotOffset the offset from binding root to the reserved slot
* @param pureFn Function that returns an updated value
* @param exp Updated expression value
* @param thisArg Optional calling context of pureFn
@ -41,20 +51,18 @@ export function pureFunction0<T>(slotOffset: number, pureFn: () => T, thisArg?:
*/
export function pureFunction1(
slotOffset: number, pureFn: (v: any) => any, exp: any, thisArg?: any): any {
ngDevMode && assertReservedSlotInitialized(slotOffset, 2);
const index = moveBindingIndexToReservedSlot(slotOffset);
const value = bindingUpdated(exp) ?
checkAndUpdateBinding(thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) :
consumeBinding();
restoreBindingIndex(index);
return value;
initBindings(); // TODO(kara): remove this check when we have pre-filled array
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated(bindingIndex, exp) ?
updateBinding(bindingIndex + 1, thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) :
getBinding(bindingIndex + 1);
}
/**
* If the value of any provided exp has changed, calls the pure function to return
* an updated value. Or if no values have changed, returns cached value.
*
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
* @param slotOffset the offset from binding root to the reserved slot
* @param pureFn
* @param exp1
* @param exp2
@ -64,20 +72,19 @@ export function pureFunction1(
export function pureFunction2(
slotOffset: number, pureFn: (v1: any, v2: any) => any, exp1: any, exp2: any,
thisArg?: any): any {
ngDevMode && assertReservedSlotInitialized(slotOffset, 3);
const index = moveBindingIndexToReservedSlot(slotOffset);
const value = bindingUpdated2(exp1, exp2) ?
checkAndUpdateBinding(thisArg ? pureFn.call(thisArg, exp1, exp2) : pureFn(exp1, exp2)) :
consumeBinding();
restoreBindingIndex(index);
return value;
initBindings(); // TODO(kara): remove this check when we have pre-filled array
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated2(bindingIndex, exp1, exp2) ?
updateBinding(
bindingIndex + 2, thisArg ? pureFn.call(thisArg, exp1, exp2) : pureFn(exp1, exp2)) :
getBinding(bindingIndex + 2);
}
/**
* If the value of any provided exp has changed, calls the pure function to return
* an updated value. Or if no values have changed, returns cached value.
*
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
* @param slotOffset the offset from binding root to the reserved slot
* @param pureFn
* @param exp1
* @param exp2
@ -88,22 +95,20 @@ export function pureFunction2(
export function pureFunction3(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any) => any, exp1: any, exp2: any, exp3: any,
thisArg?: any): any {
ngDevMode && assertReservedSlotInitialized(slotOffset, 4);
const index = moveBindingIndexToReservedSlot(slotOffset);
const different = bindingUpdated2(exp1, exp2);
const value = bindingUpdated(exp3) || different ?
checkAndUpdateBinding(
initBindings(); // TODO(kara): remove this check when we have pre-filled array
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated3(bindingIndex, exp1, exp2, exp3) ?
updateBinding(
bindingIndex + 3,
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3) : pureFn(exp1, exp2, exp3)) :
consumeBinding();
restoreBindingIndex(index);
return value;
getBinding(bindingIndex + 3);
}
/**
* If the value of any provided exp has changed, calls the pure function to return
* an updated value. Or if no values have changed, returns cached value.
*
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
* @param slotOffset the offset from binding root to the reserved slot
* @param pureFn
* @param exp1
* @param exp2
@ -115,21 +120,20 @@ export function pureFunction3(
export function pureFunction4(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any) => any, exp1: any, exp2: any,
exp3: any, exp4: any, thisArg?: any): any {
ngDevMode && assertReservedSlotInitialized(slotOffset, 5);
const index = moveBindingIndexToReservedSlot(slotOffset);
const value = bindingUpdated4(exp1, exp2, exp3, exp4) ?
checkAndUpdateBinding(
initBindings(); // TODO(kara): remove this check when we have pre-filled array
const bindingIndex = getTView().bindingStartIndex + slotOffset;
return bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4) ?
updateBinding(
bindingIndex + 4,
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4) : pureFn(exp1, exp2, exp3, exp4)) :
consumeBinding();
restoreBindingIndex(index);
return value;
getBinding(bindingIndex + 4);
}
/**
* If the value of any provided exp has changed, calls the pure function to return
* an updated value. Or if no values have changed, returns cached value.
*
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
* @param slotOffset the offset from binding root to the reserved slot
* @param pureFn
* @param exp1
* @param exp2
@ -142,23 +146,21 @@ export function pureFunction4(
export function pureFunction5(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any) => any, exp1: any,
exp2: any, exp3: any, exp4: any, exp5: any, thisArg?: any): any {
ngDevMode && assertReservedSlotInitialized(slotOffset, 6);
const index = moveBindingIndexToReservedSlot(slotOffset);
const different = bindingUpdated4(exp1, exp2, exp3, exp4);
const value = bindingUpdated(exp5) || different ?
checkAndUpdateBinding(
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) :
pureFn(exp1, exp2, exp3, exp4, exp5)) :
consumeBinding();
restoreBindingIndex(index);
return value;
initBindings(); // TODO(kara): remove this check when we have pre-filled array
const bindingIndex = getTView().bindingStartIndex + slotOffset;
const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated(bindingIndex + 4, exp5) || different ?
updateBinding(
bindingIndex + 5, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) :
pureFn(exp1, exp2, exp3, exp4, exp5)) :
getBinding(bindingIndex + 5);
}
/**
* If the value of any provided exp has changed, calls the pure function to return
* an updated value. Or if no values have changed, returns cached value.
*
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
* @param slotOffset the offset from binding root to the reserved slot
* @param pureFn
* @param exp1
* @param exp2
@ -172,23 +174,21 @@ export function pureFunction5(
export function pureFunction6(
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any) => any,
exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, thisArg?: any): any {
ngDevMode && assertReservedSlotInitialized(slotOffset, 7);
const index = moveBindingIndexToReservedSlot(slotOffset);
const different = bindingUpdated4(exp1, exp2, exp3, exp4);
const value = bindingUpdated2(exp5, exp6) || different ?
checkAndUpdateBinding(
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) :
pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) :
consumeBinding();
restoreBindingIndex(index);
return value;
initBindings(); // TODO(kara): remove this check when we have pre-filled array
const bindingIndex = getTView().bindingStartIndex + slotOffset;
const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated2(bindingIndex + 4, exp5, exp6) || different ?
updateBinding(
bindingIndex + 6, thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) :
pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) :
getBinding(bindingIndex + 6);
}
/**
* If the value of any provided exp has changed, calls the pure function to return
* an updated value. Or if no values have changed, returns cached value.
*
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
* @param slotOffset the offset from binding root to the reserved slot
* @param pureFn
* @param exp1
* @param exp2
@ -204,24 +204,22 @@ export function pureFunction7(
slotOffset: number,
pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any) => any, exp1: any,
exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, thisArg?: any): any {
ngDevMode && assertReservedSlotInitialized(slotOffset, 8);
const index = moveBindingIndexToReservedSlot(slotOffset);
let different = bindingUpdated4(exp1, exp2, exp3, exp4);
different = bindingUpdated2(exp5, exp6) || different;
const value = bindingUpdated(exp7) || different ?
checkAndUpdateBinding(
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) :
pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) :
consumeBinding();
restoreBindingIndex(index);
return value;
initBindings(); // TODO(kara): remove this check when we have pre-filled array
const bindingIndex = getTView().bindingStartIndex + slotOffset;
let different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated3(bindingIndex + 4, exp5, exp6, exp7) || different ?
updateBinding(
bindingIndex + 7, thisArg ?
pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) :
pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) :
getBinding(bindingIndex + 7);
}
/**
* If the value of any provided exp has changed, calls the pure function to return
* an updated value. Or if no values have changed, returns cached value.
*
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
* @param slotOffset the offset from binding root to the reserved slot
* @param pureFn
* @param exp1
* @param exp2
@ -239,16 +237,15 @@ export function pureFunction8(
pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any) => any,
exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, exp8: any,
thisArg?: any): any {
ngDevMode && assertReservedSlotInitialized(slotOffset, 9);
const index = moveBindingIndexToReservedSlot(slotOffset);
const different = bindingUpdated4(exp1, exp2, exp3, exp4);
const value = bindingUpdated4(exp5, exp6, exp7, exp8) || different ?
checkAndUpdateBinding(
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) :
pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) :
consumeBinding();
restoreBindingIndex(index);
return value;
initBindings(); // TODO(kara): remove this check when we have pre-filled array
const bindingIndex = getTView().bindingStartIndex + slotOffset;
const different = bindingUpdated4(bindingIndex, exp1, exp2, exp3, exp4);
return bindingUpdated4(bindingIndex + 4, exp5, exp6, exp7, exp8) || different ?
updateBinding(
bindingIndex + 8, thisArg ?
pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) :
pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) :
getBinding(bindingIndex + 8);
}
/**
@ -257,7 +254,7 @@ export function pureFunction8(
* If the value of any provided exp has changed, calls the pure function to return
* an updated value. Or if no values have changed, returns cached value.
*
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
* @param slotOffset the offset from binding root to the reserved slot
* @param pureFn A pure function that takes binding values and builds an object or array
* containing those values.
* @param exps An array of binding values
@ -266,14 +263,12 @@ export function pureFunction8(
*/
export function pureFunctionV(
slotOffset: number, pureFn: (...v: any[]) => any, exps: any[], thisArg?: any): any {
ngDevMode && assertReservedSlotInitialized(slotOffset, exps.length + 1);
const index = moveBindingIndexToReservedSlot(slotOffset);
initBindings(); // TODO(kara): remove this check when we have pre-filled array
let bindingIndex = getTView().bindingStartIndex + slotOffset;
let different = false;
for (let i = 0; i < exps.length; i++) {
bindingUpdated(exps[i]) && (different = true);
bindingUpdated(bindingIndex++, exps[i]) && (different = true);
}
const value = different ? checkAndUpdateBinding(pureFn.apply(thisArg, exps)) : consumeBinding();
restoreBindingIndex(index);
return value;
return different ? updateBinding(bindingIndex, pureFn.apply(thisArg, exps)) :
getBinding(bindingIndex);
}

View File

@ -503,7 +503,6 @@ describe('components & directives', () => {
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-array-comp');
$r3$.ɵreserveSlots(1);
}
if (rf & 2) {
$r3$.ɵelementProperty(
@ -570,7 +569,6 @@ describe('components & directives', () => {
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-comp');
$r3$.ɵreserveSlots(1);
}
if (rf & 2) {
$r3$.ɵelementProperty(
@ -614,7 +612,6 @@ describe('components & directives', () => {
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-array-comp');
$r3$.ɵreserveSlots(2);
}
if (rf & 2) {
$r3$.ɵelementProperty(
@ -726,7 +723,6 @@ describe('components & directives', () => {
template: function MyApp_Template(rf: $RenderFlags$, c: $any$) {
if (rf & 1) {
$r3$.ɵelement(0, 'my-comp');
$r3$.ɵreserveSlots(10);
}
if (rf & 2) {
$r3$.ɵelementProperty(
@ -805,7 +801,6 @@ describe('components & directives', () => {
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'object-comp');
$r3$.ɵreserveSlots(2);
}
if (rf & 2) {
$r3$.ɵelementProperty(
@ -892,7 +887,6 @@ describe('components & directives', () => {
template: function MyApp_Template(rf: $RenderFlags$, ctx: $MyApp$) {
if (rf & 1) {
$r3$.ɵelement(0, 'nested-comp');
$r3$.ɵreserveSlots(7);
}
if (rf & 2) {
$r3$.ɵelementProperty(

View File

@ -88,7 +88,6 @@ describe('pipes', () => {
$r3$.ɵtext(0);
$r3$.ɵpipe(1, 'myPipe');
$r3$.ɵpipe(2, 'myPurePipe');
$r3$.ɵreserveSlots(6);
}
if (rf & 2) {
$r3$.ɵtextBinding(
@ -150,6 +149,21 @@ describe('pipes', () => {
// /NORMATIVE
}
function MyApp_div_Template_4(rf: $RenderFlags$, ctx: any) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵtext(1);
$r3$.ɵpipe(2, 'myPurePipe');
$r3$.ɵelementEnd();
$r3$.ɵreserveSlots(3);
}
if (rf & 2) {
const $comp$ = $r3$.ɵnextContext();
$r3$.ɵtextBinding(
1, $r3$.ɵinterpolation1('', $r3$.ɵpipeBind2(2, 3, $comp$.name, $comp$.size), ''));
}
}
@Component({
template: `{{name | myPurePipe:size}}{{name | myPurePipe:size}}
<div *oneTimeIf="more">{{name | myPurePipe:size}}</div>`
@ -170,7 +184,7 @@ describe('pipes', () => {
$r3$.ɵpipe(1, 'myPurePipe');
$r3$.ɵtext(2);
$r3$.ɵpipe(3, 'myPurePipe');
$r3$.ɵtemplate(4, C4, '', ['oneTimeIf', '']);
$r3$.ɵtemplate(4, MyApp_div_Template_4, '', ['oneTimeIf', '']);
$r3$.ɵreserveSlots(6);
}
if (rf & 2) {
@ -182,20 +196,6 @@ describe('pipes', () => {
$r3$.ɵcontainerRefreshStart(4);
$r3$.ɵcontainerRefreshEnd();
}
function C4(rf: $RenderFlags$, ctx1: $any$) {
if (rf & 1) {
$r3$.ɵelementStart(0, 'div');
$r3$.ɵtext(1);
$r3$.ɵpipe(2, 'myPurePipe');
$r3$.ɵelementEnd();
$r3$.ɵreserveSlots(3);
}
if (rf & 2) {
$r3$.ɵtextBinding(
1, $r3$.ɵinterpolation1('', $r3$.ɵpipeBind2(2, 3, ctx.name, ctx.size), ''));
}
}
}
});
// /NORMATIVE

View File

@ -10,7 +10,7 @@ import {Directive, OnChanges, OnDestroy, Pipe, PipeTransform} from '@angular/cor
import {expect} from '@angular/platform-browser/testing/src/matchers';
import {defineDirective, definePipe} from '../../src/render3/definition';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, reserveSlots, text, textBinding} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {pipe, pipeBind1, pipeBind3, pipeBind4, pipeBindV} from '../../src/render3/pipe';
@ -38,10 +38,9 @@ describe('pipe', () => {
if (rf & RenderFlags.Create) {
text(0);
pipe(1, 'countingPipe');
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, 2, person.name), ''));
textBinding(0, interpolation1('', pipeBind1(1, 1, person.name), ''));
}
}
@ -54,10 +53,9 @@ describe('pipe', () => {
if (rf & RenderFlags.Create) {
text(0);
pipe(1, 'randomPipeName');
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, 2, ctx.value), ''));
textBinding(0, interpolation1('', pipeBind1(1, 1, ctx.value), ''));
}
}, [], pipes);
@ -99,10 +97,9 @@ describe('pipe', () => {
elementStart(0, 'div', ['myDir', '']);
pipe(1, 'double');
elementEnd();
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'elprop', bind(pipeBind1(1, 2, ctx)));
elementProperty(0, 'elprop', bind(pipeBind1(1, 1, ctx)));
directive = loadDirective(0);
}
}
@ -115,11 +112,10 @@ describe('pipe', () => {
if (rf & RenderFlags.Create) {
text(0);
pipe(1, 'multiArgPipe');
reserveSlots(4);
}
if (rf & RenderFlags.Update) {
textBinding(
0, interpolation1('', pipeBind3(1, 4, person.name, 'one', person.address !.city), ''));
0, interpolation1('', pipeBind3(1, 1, person.name, 'one', person.address !.city), ''));
}
}
@ -133,12 +129,11 @@ describe('pipe', () => {
text(0);
pipe(1, 'multiArgPipe');
pipe(2, 'multiArgPipe');
reserveSlots(9);
}
if (rf & RenderFlags.Update) {
textBinding(
0, interpolation1(
'', pipeBind4(2, 9, pipeBindV(1, 4, [person.name, 'a', 'b']), 0, 1, 2), ''));
'', pipeBind4(2, 5, pipeBindV(1, 1, [person.name, 'a', 'b']), 0, 1, 2), ''));
}
}
@ -163,10 +158,9 @@ describe('pipe', () => {
elementStart(0, 'div');
pipe(1, 'identityPipe');
elementEnd();
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'someProp', bind(pipeBind1(1, 2, 'Megatron')));
elementProperty(0, 'someProp', bind(pipeBind1(1, 1, 'Megatron')));
}
}
@ -184,10 +178,9 @@ describe('pipe', () => {
if (rf & RenderFlags.Create) {
text(0);
pipe(1, 'countingPipe');
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, 2, person.name), ''));
textBinding(0, interpolation1('', pipeBind1(1, 1, person.name), ''));
}
}
@ -214,10 +207,9 @@ describe('pipe', () => {
if (rf & RenderFlags.Create) {
text(0);
pipe(1, 'countingImpurePipe');
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, 2, person.name), ''));
textBinding(0, interpolation1('', pipeBind1(1, 1, person.name), ''));
}
}
@ -236,7 +228,6 @@ describe('pipe', () => {
pipe(3, 'countingImpurePipe');
elementEnd();
container(4);
reserveSlots(4);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'someProp', bind(pipeBind1(1, 2, true)));
@ -251,10 +242,9 @@ describe('pipe', () => {
elementStart(0, 'div');
pipe(1, 'countingImpurePipe');
elementEnd();
reserveSlots(2);
}
if (rf1 & RenderFlags.Update) {
elementProperty(0, 'someProp', bind(pipeBind1(1, 2, true)));
elementProperty(0, 'someProp', bind(pipeBind1(1, 1, true)));
pipeInstances.push(load<CountingImpurePipe>(1));
}
}
@ -306,10 +296,9 @@ describe('pipe', () => {
if (rf1 & RenderFlags.Create) {
text(0);
pipe(1, 'pipeWithOnDestroy');
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
textBinding(0, interpolation1('', pipeBind1(1, 2, person.age), ''));
textBinding(0, interpolation1('', pipeBind1(1, 1, person.age), ''));
}
}
embeddedViewEnd();

View File

@ -5,11 +5,12 @@
* 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 {defineComponent} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, reserveSlots} from '../../src/render3/instructions';
import {AttributeMarker, defineComponent, template} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, loadDirective, nextContext} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunction5, pureFunction6, pureFunction7, pureFunction8, pureFunctionV} from '../../src/render3/pure_function';
import {renderToHtml} from '../../test/render3/render_util';
import {ComponentFixture, createComponent, renderToHtml} from '../../test/render3/render_util';
import {NgIf} from './common_with_def';
describe('array literals', () => {
let myComp: MyComp;
@ -36,10 +37,9 @@ describe('array literals', () => {
function Template(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'my-comp');
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'names', bind(pureFunction1(2, e0_ff, ctx.customName)));
elementProperty(0, 'names', bind(pureFunction1(1, e0_ff, ctx.customName)));
}
}
@ -64,6 +64,39 @@ describe('array literals', () => {
expect(myComp !.names).toEqual(['should not be overwritten']);
});
it('should support array literals in dynamic views', () => {
const e0_ff = (v: any) => ['Nancy', v, 'Bess'];
function IfTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'my-comp');
}
if (rf & RenderFlags.Update) {
const comp = nextContext();
elementProperty(0, 'names', bind(pureFunction1(1, e0_ff, comp.customName)));
}
}
/**
* <my-comp *ngIf="showing" [names]="['Nancy', customName, 'Bess']"></my-comp>
*/
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(0, IfTemplate, null, [AttributeMarker.SelectOnly, 'ngIf']);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'ngIf', bind(ctx.showing));
}
}, [MyComp, NgIf]);
const fixture = new ComponentFixture(App);
fixture.component.showing = true;
fixture.component.customName = 'Carson';
fixture.update();
expect(myComp !.names).toEqual(['Nancy', 'Carson', 'Bess']);
});
it('should support multiple array literals passed through to one node', () => {
let manyPropComp: ManyPropComp;
@ -92,7 +125,6 @@ describe('array literals', () => {
function Template(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'many-prop-comp');
reserveSlots(4);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'names1', bind(pureFunction1(2, e0_ff, ctx.customName)));
@ -133,10 +165,9 @@ describe('array literals', () => {
elementStart(0, 'my-comp');
myComps.push(loadDirective(0));
elementEnd();
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'names', bind(ctx.someFn(pureFunction1(2, e0_ff, ctx.customName))));
elementProperty(0, 'names', bind(ctx.someFn(pureFunction1(1, e0_ff, ctx.customName))));
}
},
directives: directives
@ -171,10 +202,9 @@ describe('array literals', () => {
function Template(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'my-comp');
reserveSlots(3);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'names', bind(pureFunction2(3, e0_ff, ctx.customName, ctx.customName2)));
elementProperty(0, 'names', bind(pureFunction2(1, e0_ff, ctx.customName, ctx.customName2)));
}
}
@ -243,19 +273,18 @@ describe('array literals', () => {
elementStart(5, 'my-comp');
f8Comp = loadDirective(5);
elementEnd();
reserveSlots(39);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'names', bind(pureFunction3(4, e0_ff, c[5], c[6], c[7])));
elementProperty(1, 'names', bind(pureFunction4(9, e2_ff, c[4], c[5], c[6], c[7])));
elementProperty(0, 'names', bind(pureFunction3(6, e0_ff, c[5], c[6], c[7])));
elementProperty(1, 'names', bind(pureFunction4(10, e2_ff, c[4], c[5], c[6], c[7])));
elementProperty(2, 'names', bind(pureFunction5(15, e4_ff, c[3], c[4], c[5], c[6], c[7])));
elementProperty(
3, 'names', bind(pureFunction6(22, e6_ff, c[2], c[3], c[4], c[5], c[6], c[7])));
3, 'names', bind(pureFunction6(21, e6_ff, c[2], c[3], c[4], c[5], c[6], c[7])));
elementProperty(
4, 'names', bind(pureFunction7(30, e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
4, 'names', bind(pureFunction7(28, e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
elementProperty(
5, 'names',
bind(pureFunction8(39, e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
bind(pureFunction8(36, e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
}
}
@ -298,12 +327,11 @@ describe('array literals', () => {
function Template(rf: RenderFlags, c: any) {
if (rf & RenderFlags.Create) {
element(0, 'my-comp');
reserveSlots(12);
}
if (rf & RenderFlags.Update) {
elementProperty(
0, 'names', bind(pureFunctionV(12, e0_ff, [
c[0], c[1], c[2], c[3], pureFunction1(2, e0_ff_1, c[4]), c[5], c[6], c[7], c[8]
0, 'names', bind(pureFunctionV(3, e0_ff, [
c[0], c[1], c[2], c[3], pureFunction1(1, e0_ff_1, c[4]), c[5], c[6], c[7], c[8]
])));
}
}
@ -349,10 +377,9 @@ describe('object literals', () => {
function Template(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'object-comp');
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'config', bind(pureFunction1(2, e0_ff, ctx.name)));
elementProperty(0, 'config', bind(pureFunction1(1, e0_ff, ctx.name)));
}
}
@ -384,13 +411,12 @@ describe('object literals', () => {
function Template(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'object-comp');
reserveSlots(7);
}
if (rf & RenderFlags.Update) {
elementProperty(
0, 'config', bind(pureFunction2(
7, e0_ff, ctx.name,
pureFunction1(4, e0_ff_1, pureFunction1(2, e0_ff_2, ctx.duration)))));
5, e0_ff, ctx.name,
pureFunction1(3, e0_ff_1, pureFunction1(1, e0_ff_2, ctx.duration)))));
}
}
@ -456,12 +482,11 @@ describe('object literals', () => {
elementStart(0, 'object-comp');
objectComps.push(loadDirective(0));
elementEnd();
reserveSlots(3);
}
if (rf1 & RenderFlags.Update) {
elementProperty(
0, 'config',
bind(pureFunction2(3, e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration)));
bind(pureFunction2(1, e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration)));
}
embeddedViewEnd();
}

View File

@ -9,7 +9,7 @@
import {Component, ComponentFactoryResolver, ElementRef, EmbeddedViewRef, NgModuleRef, Pipe, PipeTransform, RendererFactory2, TemplateRef, ViewContainerRef, createInjector, defineInjector, ɵAPP_ROOT as APP_ROOT, ɵNgModuleDef as NgModuleDef} from '../../src/core';
import {templateRefExtractor} from '../../src/render3/di';
import {AttributeMarker, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, loadDirective, nextContext, projection, projectionDef, reference, reserveSlots, template, text, textBinding} from '../../src/render3/instructions';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, loadDirective, nextContext, projection, projectionDef, reference, template, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {NgModuleFactory} from '../../src/render3/ng_module_ref';
import {pipe, pipeBind1} from '../../src/render3/pipe';
@ -410,6 +410,16 @@ describe('ViewContainerRef', () => {
});
}
function SomeComponent_Template_0(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'child');
pipe(1, 'starPipe');
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'name', bind(pipeBind1(1, 2, 'C')));
}
}
@Component({
template: `
<ng-template #foo>
@ -426,21 +436,11 @@ describe('ViewContainerRef', () => {
factory: () => new SomeComponent(),
template: (rf: RenderFlags, cmp: SomeComponent) => {
if (rf & RenderFlags.Create) {
template(0, (rf: RenderFlags, ctx: any) => {
if (rf & RenderFlags.Create) {
element(0, 'child');
pipe(1, 'starPipe');
reserveSlots(2);
}
if (rf & RenderFlags.Update) {
elementProperty(0, 'name', bind(pipeBind1(1, 2, 'C')));
}
}, null, [], ['foo', ''], templateRefExtractor);
template(0, SomeComponent_Template_0, null, [], ['foo', ''], templateRefExtractor);
pipe(2, 'starPipe');
element(3, 'child', ['vcref', '']);
pipe(4, 'starPipe');
element(5, 'child');
reserveSlots(4);
}
if (rf & RenderFlags.Update) {
const tplRef = reference(1);