feat(ivy): add support for short-circuiting (#24039)
Short-circuitable expressions (using ternary & binary operators) could not use the regular binding mechanism as it relies on the bindings being checked every single time - the index is incremented as part of checking the bindings. Then for pure function kind of bindings we use a different mechanism with a fixed index. As such short circuiting a binding check does not mess with the expected binding index. Note that all pure function bindings are handled the same wether or not they actually are short-circuitable. This allows to keep the compiler and compiled code simple - and there is no runtime perf cost anyway. PR Close #24039
This commit is contained in:
parent
83bb5d1922
commit
4f36340de7
|
@ -121,4 +121,7 @@ export class Identifiers {
|
||||||
static NgOnChangesFeature: o.ExternalReference = {name: 'ɵNgOnChangesFeature', moduleName: CORE};
|
static NgOnChangesFeature: o.ExternalReference = {name: 'ɵNgOnChangesFeature', moduleName: CORE};
|
||||||
|
|
||||||
static listener: o.ExternalReference = {name: 'ɵL', moduleName: CORE};
|
static listener: o.ExternalReference = {name: 'ɵL', moduleName: CORE};
|
||||||
|
|
||||||
|
// Reserve slots for pure functions
|
||||||
|
static reserveSlots: o.ExternalReference = {name: 'ɵrS', moduleName: CORE};
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,9 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
// Maps of placeholder to node indexes for each of the i18n section
|
// Maps of placeholder to node indexes for each of the i18n section
|
||||||
private _phToNodeIdxes: {[phName: string]: number[]}[] = [{}];
|
private _phToNodeIdxes: {[phName: string]: number[]}[] = [{}];
|
||||||
|
|
||||||
|
// Number of slots to reserve for pureFunctions
|
||||||
|
private _pureFunctionSlots = 0;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private constantPool: ConstantPool, private contextParameter: string,
|
private constantPool: ConstantPool, private contextParameter: string,
|
||||||
parentBindingScope: BindingScope, private level = 0, private contextName: string|null,
|
parentBindingScope: BindingScope, private level = 0, private contextName: string|null,
|
||||||
|
@ -70,6 +73,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
});
|
});
|
||||||
this._valueConverter = new ValueConverter(
|
this._valueConverter = new ValueConverter(
|
||||||
constantPool, () => this.allocateDataSlot(),
|
constantPool, () => this.allocateDataSlot(),
|
||||||
|
(numSlots: number): number => this._pureFunctionSlots += numSlots,
|
||||||
(name, localName, slot, value: o.ReadVarExpr) => {
|
(name, localName, slot, value: o.ReadVarExpr) => {
|
||||||
const pipeType = pipeTypeByName.get(name);
|
const pipeType = pipeTypeByName.get(name);
|
||||||
if (pipeType) {
|
if (pipeType) {
|
||||||
|
@ -139,6 +143,11 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
|
|
||||||
t.visitAll(this, nodes);
|
t.visitAll(this, nodes);
|
||||||
|
|
||||||
|
if (this._pureFunctionSlots > 0) {
|
||||||
|
this.instruction(
|
||||||
|
this._creationCode, null, R3.reserveSlots, o.literal(this._pureFunctionSlots));
|
||||||
|
}
|
||||||
|
|
||||||
const creationCode = this._creationCode.length > 0 ?
|
const creationCode = this._creationCode.length > 0 ?
|
||||||
[o.ifStmt(
|
[o.ifStmt(
|
||||||
o.variable(RENDER_FLAGS).bitwiseAnd(o.literal(core.RenderFlags.Create), null, false),
|
o.variable(RENDER_FLAGS).bitwiseAnd(o.literal(core.RenderFlags.Create), null, false),
|
||||||
|
@ -501,6 +510,7 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
|
||||||
class ValueConverter extends AstMemoryEfficientTransformer {
|
class ValueConverter extends AstMemoryEfficientTransformer {
|
||||||
constructor(
|
constructor(
|
||||||
private constantPool: ConstantPool, private allocateSlot: () => number,
|
private constantPool: ConstantPool, private allocateSlot: () => number,
|
||||||
|
private allocatePureFunctionSlots: (numSlots: number) => number,
|
||||||
private definePipe:
|
private definePipe:
|
||||||
(name: string, localName: string, slot: number, value: o.Expression) => void) {
|
(name: string, localName: string, slot: number, value: o.Expression) => void) {
|
||||||
super();
|
super();
|
||||||
|
@ -511,14 +521,20 @@ class ValueConverter extends AstMemoryEfficientTransformer {
|
||||||
// Allocate a slot to create the pipe
|
// Allocate a slot to create the pipe
|
||||||
const slot = this.allocateSlot();
|
const slot = this.allocateSlot();
|
||||||
const slotPseudoLocal = `PIPE:${slot}`;
|
const slotPseudoLocal = `PIPE:${slot}`;
|
||||||
|
// Allocate one slot for the result plus one slot per pipe argument
|
||||||
|
const pureFunctionSlot = this.allocatePureFunctionSlots(2 + pipe.args.length);
|
||||||
const target = new PropertyRead(pipe.span, new ImplicitReceiver(pipe.span), slotPseudoLocal);
|
const target = new PropertyRead(pipe.span, new ImplicitReceiver(pipe.span), slotPseudoLocal);
|
||||||
const bindingId = pipeBinding(pipe.args);
|
const bindingId = pipeBinding(pipe.args);
|
||||||
this.definePipe(pipe.name, slotPseudoLocal, slot, o.importExpr(bindingId));
|
this.definePipe(pipe.name, slotPseudoLocal, slot, o.importExpr(bindingId));
|
||||||
const value = pipe.exp.visit(this);
|
const value = pipe.exp.visit(this);
|
||||||
const args = this.visitAll(pipe.args);
|
const args = this.visitAll(pipe.args);
|
||||||
|
|
||||||
return new FunctionCall(
|
return new FunctionCall(pipe.span, target, [
|
||||||
pipe.span, target, [new LiteralPrimitive(pipe.span, slot), value, ...args]);
|
new LiteralPrimitive(pipe.span, slot),
|
||||||
|
new LiteralPrimitive(pipe.span, pureFunctionSlot),
|
||||||
|
value,
|
||||||
|
...args,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
visitLiteralArray(array: LiteralArray, context: any): AST {
|
visitLiteralArray(array: LiteralArray, context: any): AST {
|
||||||
|
@ -527,8 +543,9 @@ class ValueConverter extends AstMemoryEfficientTransformer {
|
||||||
// calls to literal factories that compose the literal and will cache intermediate
|
// calls to literal factories that compose the literal and will cache intermediate
|
||||||
// values. Otherwise, just return an literal array that contains the values.
|
// values. Otherwise, just return an literal array that contains the values.
|
||||||
const literal = o.literalArr(values);
|
const literal = o.literalArr(values);
|
||||||
return values.every(a => a.isConstant()) ? this.constantPool.getConstLiteral(literal, true) :
|
return values.every(a => a.isConstant()) ?
|
||||||
getLiteralFactory(this.constantPool, literal);
|
this.constantPool.getConstLiteral(literal, true) :
|
||||||
|
getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,14 +556,13 @@ class ValueConverter extends AstMemoryEfficientTransformer {
|
||||||
// values. Otherwise, just return an literal array that contains the values.
|
// values. Otherwise, just return an literal array that contains the values.
|
||||||
const literal = o.literalMap(values.map(
|
const literal = o.literalMap(values.map(
|
||||||
(value, index) => ({key: map.keys[index].key, value, quoted: map.keys[index].quoted})));
|
(value, index) => ({key: map.keys[index].key, value, quoted: map.keys[index].quoted})));
|
||||||
return values.every(a => a.isConstant()) ? this.constantPool.getConstLiteral(literal, true) :
|
return values.every(a => a.isConstant()) ?
|
||||||
getLiteralFactory(this.constantPool, literal);
|
this.constantPool.getConstLiteral(literal, true) :
|
||||||
|
getLiteralFactory(this.constantPool, literal, this.allocatePureFunctionSlots);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Pipes always have at least one parameter, the value they operate on
|
// Pipes always have at least one parameter, the value they operate on
|
||||||
const pipeBindingIdentifiers = [R3.pipeBind1, R3.pipeBind2, R3.pipeBind3, R3.pipeBind4];
|
const pipeBindingIdentifiers = [R3.pipeBind1, R3.pipeBind2, R3.pipeBind3, R3.pipeBind4];
|
||||||
|
|
||||||
|
@ -559,15 +575,20 @@ const pureFunctionIdentifiers = [
|
||||||
R3.pureFunction5, R3.pureFunction6, R3.pureFunction7, R3.pureFunction8
|
R3.pureFunction5, R3.pureFunction6, R3.pureFunction7, R3.pureFunction8
|
||||||
];
|
];
|
||||||
function getLiteralFactory(
|
function getLiteralFactory(
|
||||||
constantPool: ConstantPool, literal: o.LiteralArrayExpr | o.LiteralMapExpr): o.Expression {
|
constantPool: ConstantPool, literal: o.LiteralArrayExpr | o.LiteralMapExpr,
|
||||||
|
allocateSlots: (numSlots: number) => number): o.Expression {
|
||||||
const {literalFactory, literalFactoryArguments} = constantPool.getLiteralFactory(literal);
|
const {literalFactory, literalFactoryArguments} = constantPool.getLiteralFactory(literal);
|
||||||
|
// Allocate 1 slot for the result plus 1 per argument
|
||||||
|
const startSlot = allocateSlots(1 + literalFactoryArguments.length);
|
||||||
literalFactoryArguments.length > 0 || error(`Expected arguments to a literal factory function`);
|
literalFactoryArguments.length > 0 || error(`Expected arguments to a literal factory function`);
|
||||||
let pureFunctionIdent =
|
let pureFunctionIdent =
|
||||||
pureFunctionIdentifiers[literalFactoryArguments.length] || R3.pureFunctionV;
|
pureFunctionIdentifiers[literalFactoryArguments.length] || R3.pureFunctionV;
|
||||||
|
|
||||||
// Literal factories are pure functions that only need to be re-invoked when the parameters
|
// Literal factories are pure functions that only need to be re-invoked when the parameters
|
||||||
// change.
|
// change.
|
||||||
return o.importExpr(pureFunctionIdent).callFn([literalFactory, ...literalFactoryArguments]);
|
return o.importExpr(pureFunctionIdent).callFn([
|
||||||
|
o.literal(startSlot), literalFactory, ...literalFactoryArguments
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -107,6 +107,57 @@ describe('compiler compliance', () => {
|
||||||
expectEmit(result.source, template, 'Incorrect template');
|
expectEmit(result.source, template, 'Incorrect template');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should reserve slots for pure functions', () => {
|
||||||
|
const files = {
|
||||||
|
app: {
|
||||||
|
'spec.ts': `
|
||||||
|
import {Component, NgModule} from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'my-component',
|
||||||
|
template: \`<div
|
||||||
|
[ternary]="cond ? [a] : [0]"
|
||||||
|
[pipe]="value | pipe:1:2"
|
||||||
|
[and]="cond && [b]"
|
||||||
|
[or]="cond || [c]"
|
||||||
|
></div>\`
|
||||||
|
})
|
||||||
|
export class MyComponent {
|
||||||
|
id = 'one';
|
||||||
|
}
|
||||||
|
|
||||||
|
@NgModule({declarations: [MyComponent]})
|
||||||
|
export class MyModule {}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const factory = 'factory: function MyComponent_Factory() { return new MyComponent(); }';
|
||||||
|
const template = `
|
||||||
|
…
|
||||||
|
template: function MyComponent_Template(rf: IDENT, ctx: IDENT) {
|
||||||
|
if (rf & 1) {
|
||||||
|
$r3$.ɵE(0, 'div');
|
||||||
|
$r3$.ɵPp(1,'pipe');
|
||||||
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(10);
|
||||||
|
}
|
||||||
|
if (rf & 2) {
|
||||||
|
$r3$.ɵp(0, 'ternary', $r3$.ɵb((ctx.cond ? $r3$.ɵf1(2, _c0, ctx.a): _c1)));
|
||||||
|
$r3$.ɵp(0, 'pipe', $r3$.ɵb($r3$.ɵpb3(6, 1, ctx.value, 1, 2)));
|
||||||
|
$r3$.ɵp(0, 'and', $r3$.ɵb((ctx.cond && $r3$.ɵf1(4, _c0, ctx.b))));
|
||||||
|
$r3$.ɵp(0, 'or', $r3$.ɵb((ctx.cond || $r3$.ɵf1(6, _c0, ctx.c))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
|
const result = compile(files, angularFiles);
|
||||||
|
|
||||||
|
expectEmit(result.source, factory, 'Incorrect factory');
|
||||||
|
expectEmit(result.source, template, 'Incorrect template');
|
||||||
|
});
|
||||||
|
|
||||||
it('should bind to class and style names', () => {
|
it('should bind to class and style names', () => {
|
||||||
const files = {
|
const files = {
|
||||||
app: {
|
app: {
|
||||||
|
@ -415,9 +466,10 @@ describe('compiler compliance', () => {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-comp');
|
$r3$.ɵE(0, 'my-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(2);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(0, 'names', $r3$.ɵb($r3$.ɵf1($e0_ff$, ctx.customName)));
|
$r3$.ɵp(0, 'names', $r3$.ɵb($r3$.ɵf1(2, $e0_ff$, ctx.customName)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directives: [MyComp]
|
directives: [MyComp]
|
||||||
|
@ -494,11 +546,12 @@ describe('compiler compliance', () => {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-comp');
|
$r3$.ɵE(0, 'my-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(10);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(
|
$r3$.ɵp(
|
||||||
0, 'names',
|
0, 'names',
|
||||||
$r3$.ɵb($r3$.ɵfV($e0_ff$, ctx.n0, ctx.n1, ctx.n2, ctx.n3, ctx.n4, ctx.n5, ctx.n6, ctx.n7, ctx.n8)));
|
$r3$.ɵb($r3$.ɵfV(10, $e0_ff$, ctx.n0, ctx.n1, ctx.n2, ctx.n3, ctx.n4, ctx.n5, ctx.n6, ctx.n7, ctx.n8)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directives: [MyComp]
|
directives: [MyComp]
|
||||||
|
@ -555,9 +608,10 @@ describe('compiler compliance', () => {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'object-comp');
|
$r3$.ɵE(0, 'object-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(2);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(0, 'config', $r3$.ɵb($r3$.ɵf1($e0_ff$, ctx.name)));
|
$r3$.ɵp(0, 'config', $r3$.ɵb($r3$.ɵf1(2, $e0_ff$, ctx.name)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directives: [ObjectComp]
|
directives: [ObjectComp]
|
||||||
|
@ -620,12 +674,12 @@ describe('compiler compliance', () => {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'nested-comp');
|
$r3$.ɵE(0, 'nested-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(7);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(
|
$r3$.ɵp(
|
||||||
0, 'config',
|
0, 'config',
|
||||||
$r3$.ɵb($r3$.ɵf2(
|
$r3$.ɵb($r3$.ɵf2(7, $e0_ff_2$, ctx.name, $r3$.ɵf1(4, $e0_ff_1$, $r3$.ɵf1(2, $e0_ff$, ctx.duration)))));
|
||||||
$e0_ff_2$, ctx.name, $r3$.ɵf1($e0_ff_1$, $r3$.ɵf1($e0_ff$, ctx.duration)))));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directives: [NestedComp]
|
directives: [NestedComp]
|
||||||
|
@ -912,10 +966,11 @@ describe('compiler compliance', () => {
|
||||||
$r3$.ɵT(4);
|
$r3$.ɵT(4);
|
||||||
$r3$.ɵPp(5, 'myPurePipe');
|
$r3$.ɵPp(5, 'myPurePipe');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(9);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵt(0, $r3$.ɵi1('', $r3$.ɵpb2(1, $r3$.ɵpb2(2,ctx.name, ctx.size), ctx.size), ''));
|
$r3$.ɵt(0, $r3$.ɵi1('', $r3$.ɵpb2(1, 3, $r3$.ɵpb2(2, 6, ctx.name, ctx.size), ctx.size), ''));
|
||||||
$r3$.ɵt(4, $r3$.ɵi1('', $r3$.ɵpb2(5, ctx.name, ctx.size), ''));
|
$r3$.ɵt(4, $r3$.ɵi1('', $r3$.ɵpb2(5, 9, ctx.name, ctx.size), ''));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pipes: [MyPurePipe, MyPipe]
|
pipes: [MyPurePipe, MyPipe]
|
||||||
|
|
|
@ -65,6 +65,7 @@ export {
|
||||||
e as ɵe,
|
e as ɵe,
|
||||||
p as ɵp,
|
p as ɵp,
|
||||||
pD as ɵpD,
|
pD as ɵpD,
|
||||||
|
rS as ɵrS,
|
||||||
a as ɵa,
|
a as ɵa,
|
||||||
s as ɵs,
|
s as ɵs,
|
||||||
sn as ɵsn,
|
sn as ɵsn,
|
||||||
|
|
|
@ -64,6 +64,8 @@ export {
|
||||||
text as T,
|
text as T,
|
||||||
textBinding as t,
|
textBinding as t,
|
||||||
|
|
||||||
|
reserveSlots as rS,
|
||||||
|
|
||||||
embeddedViewStart as V,
|
embeddedViewStart as V,
|
||||||
embeddedViewEnd as v,
|
embeddedViewEnd as v,
|
||||||
detectChanges,
|
detectChanges,
|
||||||
|
|
|
@ -1446,12 +1446,10 @@ function generateInitialInputs(
|
||||||
return initialInputData;
|
return initialInputData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
//// ViewContainer & View
|
//// ViewContainer & View
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
|
||||||
|
|
||||||
export function createLContainer(
|
export function createLContainer(
|
||||||
parentLNode: LNode, currentView: LView, template?: ComponentTemplate<any>): LContainer {
|
parentLNode: LNode, currentView: LView, template?: ComponentTemplate<any>): LContainer {
|
||||||
ngDevMode && assertNotNull(parentLNode, 'containers should have a parent');
|
ngDevMode && assertNotNull(parentLNode, 'containers should have a parent');
|
||||||
|
@ -2146,6 +2144,57 @@ export function bind<T>(value: T | NO_CHANGE): T|NO_CHANGE {
|
||||||
return changed ? value : NO_CHANGE;
|
return changed ? value : NO_CHANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserves slots for pure functions (`pureFunctionX` instructions)
|
||||||
|
*
|
||||||
|
* Binding for pure functions are store after the LNodes in the data array but before the binding.
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* | LNodes ... | pure function bindings | regular bindings / interpolations |
|
||||||
|
* ----------------------------------------------------------------------------
|
||||||
|
* ^
|
||||||
|
* LView.bindingStartIndex
|
||||||
|
*
|
||||||
|
* Pure function instructions are given an offset from LView.bindingStartIndex.
|
||||||
|
* Subtracting the offset from LView.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
|
||||||
|
*/
|
||||||
|
export function reserveSlots(numSlots: number) {
|
||||||
|
// Init the slots with a unique `NO_CHANGE` value so that the first change is always detected
|
||||||
|
// whether is happens or not during the first change detection pass - pure functions checks
|
||||||
|
// might be skipped when short-circuited.
|
||||||
|
data.length += numSlots;
|
||||||
|
data.fill(NO_CHANGE, -numSlots);
|
||||||
|
// We need to initialize the binding in case a `pureFunctionX` kind of binding instruction is
|
||||||
|
// called first in the update section.
|
||||||
|
initBindings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the binding index before execute any `pureFunctionX` instructions.
|
||||||
|
*
|
||||||
|
* The index must be restored after the pure function is executed
|
||||||
|
*
|
||||||
|
* {@link reserveSlots}
|
||||||
|
*/
|
||||||
|
export function moveBindingIndexToReservedSlot(offset: number): number {
|
||||||
|
const currentSlot = currentView.bindingIndex;
|
||||||
|
currentView.bindingIndex = currentView.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 {
|
||||||
|
currentView.bindingIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create interpolation bindings with a variable number of expressions.
|
* Create interpolation bindings with a variable number of expressions.
|
||||||
*
|
*
|
||||||
|
@ -2378,6 +2427,22 @@ function assertDataNext(index: number, arr?: any[]) {
|
||||||
arr.length, index, `index ${index} expected to be at the end of arr (length ${arr.length})`);
|
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 = currentView.bindingStartIndex - slotOffset;
|
||||||
|
for (let i = 0; i < numSlots; i++) {
|
||||||
|
assertEqual(
|
||||||
|
data[startIndex + i], NO_CHANGE,
|
||||||
|
'The reserved slots should be set to `NO_CHANGE` on first template pass');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function _getComponentHostLElementNode<T>(component: T): LElementNode {
|
export function _getComponentHostLElementNode<T>(component: T): LElementNode {
|
||||||
ngDevMode && assertNotNull(component, 'expecting component got null');
|
ngDevMode && assertNotNull(component, 'expecting component got null');
|
||||||
const lElementNode = (component as any)[NG_HOST_SYMBOL] as LElementNode;
|
const lElementNode = (component as any)[NG_HOST_SYMBOL] as LElementNode;
|
||||||
|
|
|
@ -65,11 +65,12 @@ function getPipeDef(name: string, registry: PipeDefList | null): PipeDef<any> {
|
||||||
* the pipe only when an input to the pipe changes.
|
* the pipe only when an input to the pipe changes.
|
||||||
*
|
*
|
||||||
* @param index Pipe index where the pipe was stored on creation.
|
* @param index Pipe index where the pipe was stored on creation.
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param v1 1st argument to {@link PipeTransform#transform}.
|
* @param v1 1st argument to {@link PipeTransform#transform}.
|
||||||
*/
|
*/
|
||||||
export function pipeBind1(index: number, v1: any): any {
|
export function pipeBind1(index: number, slotOffset: number, v1: any): any {
|
||||||
const pipeInstance = load<PipeTransform>(index);
|
const pipeInstance = load<PipeTransform>(index);
|
||||||
return isPure(index) ? pureFunction1(pipeInstance.transform, v1, pipeInstance) :
|
return isPure(index) ? pureFunction1(slotOffset, pipeInstance.transform, v1, pipeInstance) :
|
||||||
pipeInstance.transform(v1);
|
pipeInstance.transform(v1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,12 +81,13 @@ export function pipeBind1(index: number, v1: any): any {
|
||||||
* the pipe only when an input to the pipe changes.
|
* the pipe only when an input to the pipe changes.
|
||||||
*
|
*
|
||||||
* @param index Pipe index where the pipe was stored on creation.
|
* @param index Pipe index where the pipe was stored on creation.
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param v1 1st argument to {@link PipeTransform#transform}.
|
* @param v1 1st argument to {@link PipeTransform#transform}.
|
||||||
* @param v2 2nd argument to {@link PipeTransform#transform}.
|
* @param v2 2nd argument to {@link PipeTransform#transform}.
|
||||||
*/
|
*/
|
||||||
export function pipeBind2(index: number, v1: any, v2: any): any {
|
export function pipeBind2(index: number, slotOffset: number, v1: any, v2: any): any {
|
||||||
const pipeInstance = load<PipeTransform>(index);
|
const pipeInstance = load<PipeTransform>(index);
|
||||||
return isPure(index) ? pureFunction2(pipeInstance.transform, v1, v2, pipeInstance) :
|
return isPure(index) ? pureFunction2(slotOffset, pipeInstance.transform, v1, v2, pipeInstance) :
|
||||||
pipeInstance.transform(v1, v2);
|
pipeInstance.transform(v1, v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,13 +98,15 @@ export function pipeBind2(index: number, v1: any, v2: any): any {
|
||||||
* the pipe only when an input to the pipe changes.
|
* the pipe only when an input to the pipe changes.
|
||||||
*
|
*
|
||||||
* @param index Pipe index where the pipe was stored on creation.
|
* @param index Pipe index where the pipe was stored on creation.
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param v1 1st argument to {@link PipeTransform#transform}.
|
* @param v1 1st argument to {@link PipeTransform#transform}.
|
||||||
* @param v2 2nd argument to {@link PipeTransform#transform}.
|
* @param v2 2nd argument to {@link PipeTransform#transform}.
|
||||||
* @param v3 4rd argument to {@link PipeTransform#transform}.
|
* @param v3 4rd argument to {@link PipeTransform#transform}.
|
||||||
*/
|
*/
|
||||||
export function pipeBind3(index: number, v1: any, v2: any, v3: any): any {
|
export function pipeBind3(index: number, slotOffset: number, v1: any, v2: any, v3: any): any {
|
||||||
const pipeInstance = load<PipeTransform>(index);
|
const pipeInstance = load<PipeTransform>(index);
|
||||||
return isPure(index) ? pureFunction3(pipeInstance.transform, v1, v2, v3, pipeInstance) :
|
return isPure(index) ?
|
||||||
|
pureFunction3(slotOffset, pipeInstance.transform, v1, v2, v3, pipeInstance) :
|
||||||
pipeInstance.transform(v1, v2, v3);
|
pipeInstance.transform(v1, v2, v3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,14 +117,17 @@ export function pipeBind3(index: number, v1: any, v2: any, v3: any): any {
|
||||||
* the pipe only when an input to the pipe changes.
|
* the pipe only when an input to the pipe changes.
|
||||||
*
|
*
|
||||||
* @param index Pipe index where the pipe was stored on creation.
|
* @param index Pipe index where the pipe was stored on creation.
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param v1 1st argument to {@link PipeTransform#transform}.
|
* @param v1 1st argument to {@link PipeTransform#transform}.
|
||||||
* @param v2 2nd argument to {@link PipeTransform#transform}.
|
* @param v2 2nd argument to {@link PipeTransform#transform}.
|
||||||
* @param v3 3rd argument to {@link PipeTransform#transform}.
|
* @param v3 3rd argument to {@link PipeTransform#transform}.
|
||||||
* @param v4 4th argument to {@link PipeTransform#transform}.
|
* @param v4 4th argument to {@link PipeTransform#transform}.
|
||||||
*/
|
*/
|
||||||
export function pipeBind4(index: number, v1: any, v2: any, v3: any, v4: any): any {
|
export function pipeBind4(
|
||||||
|
index: number, slotOffset: number, v1: any, v2: any, v3: any, v4: any): any {
|
||||||
const pipeInstance = load<PipeTransform>(index);
|
const pipeInstance = load<PipeTransform>(index);
|
||||||
return isPure(index) ? pureFunction4(pipeInstance.transform, v1, v2, v3, v4, pipeInstance) :
|
return isPure(index) ?
|
||||||
|
pureFunction4(slotOffset, pipeInstance.transform, v1, v2, v3, v4, pipeInstance) :
|
||||||
pipeInstance.transform(v1, v2, v3, v4);
|
pipeInstance.transform(v1, v2, v3, v4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,11 +138,12 @@ export function pipeBind4(index: number, v1: any, v2: any, v3: any, v4: any): an
|
||||||
* the pipe only when an input to the pipe changes.
|
* the pipe only when an input to the pipe changes.
|
||||||
*
|
*
|
||||||
* @param index Pipe index where the pipe was stored on creation.
|
* @param index Pipe index where the pipe was stored on creation.
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param values Array of arguments to pass to {@link PipeTransform#transform} method.
|
* @param values Array of arguments to pass to {@link PipeTransform#transform} method.
|
||||||
*/
|
*/
|
||||||
export function pipeBindV(index: number, values: any[]): any {
|
export function pipeBindV(index: number, slotOffset: number, values: any[]): any {
|
||||||
const pipeInstance = load<PipeTransform>(index);
|
const pipeInstance = load<PipeTransform>(index);
|
||||||
return isPure(index) ? pureFunctionV(pipeInstance.transform, values, pipeInstance) :
|
return isPure(index) ? pureFunctionV(slotOffset, pipeInstance.transform, values, pipeInstance) :
|
||||||
pipeInstance.transform.apply(pipeInstance, values);
|
pipeInstance.transform.apply(pipeInstance, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {bindingUpdated, bindingUpdated2, bindingUpdated4, checkAndUpdateBinding, consumeBinding, getCreationMode} from './instructions';
|
import {assertReservedSlotInitialized, bindingUpdated, bindingUpdated2, bindingUpdated4, checkAndUpdateBinding, consumeBinding, getCreationMode, moveBindingIndexToReservedSlot, restoreBindingIndex} from './instructions';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,92 +15,121 @@ import {bindingUpdated, bindingUpdated2, bindingUpdated4, checkAndUpdateBinding,
|
||||||
* value. If it has been saved, returns the saved value.
|
* value. If it has been saved, returns the saved value.
|
||||||
*
|
*
|
||||||
* @param pureFn Function that returns a value
|
* @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
|
* @param thisArg Optional calling context of pureFn
|
||||||
* @returns value
|
* @returns value
|
||||||
*/
|
*/
|
||||||
export function pureFunction0<T>(pureFn: () => T, thisArg?: any): T {
|
export function pureFunction0<T>(slotOffset: number, pureFn: () => T, thisArg?: any): T {
|
||||||
return getCreationMode() ? checkAndUpdateBinding(thisArg ? pureFn.call(thisArg) : pureFn()) :
|
ngDevMode && assertReservedSlotInitialized(slotOffset, 1);
|
||||||
|
const index = moveBindingIndexToReservedSlot(slotOffset);
|
||||||
|
const value = getCreationMode() ?
|
||||||
|
checkAndUpdateBinding(thisArg ? pureFn.call(thisArg) : pureFn()) :
|
||||||
consumeBinding();
|
consumeBinding();
|
||||||
|
restoreBindingIndex(index);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the value of the provided exp has changed, calls the pure function to return
|
* 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.
|
* 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 pureFn Function that returns an updated value
|
* @param pureFn Function that returns an updated value
|
||||||
* @param exp Updated expression value
|
* @param exp Updated expression value
|
||||||
* @param thisArg Optional calling context of pureFn
|
* @param thisArg Optional calling context of pureFn
|
||||||
* @returns Updated value
|
* @returns Updated or cached value
|
||||||
*/
|
*/
|
||||||
export function pureFunction1(pureFn: (v: any) => any, exp: any, thisArg?: any): any {
|
export function pureFunction1(
|
||||||
return bindingUpdated(exp) ?
|
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)) :
|
checkAndUpdateBinding(thisArg ? pureFn.call(thisArg, exp) : pureFn(exp)) :
|
||||||
consumeBinding();
|
consumeBinding();
|
||||||
|
restoreBindingIndex(index);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the value of any provided exp has changed, calls the pure function to return
|
* 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.
|
* an updated value. Or if no values have changed, returns cached value.
|
||||||
*
|
*
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param pureFn
|
* @param pureFn
|
||||||
* @param exp1
|
* @param exp1
|
||||||
* @param exp2
|
* @param exp2
|
||||||
* @param thisArg Optional calling context of pureFn
|
* @param thisArg Optional calling context of pureFn
|
||||||
* @returns Updated value
|
* @returns Updated or cached value
|
||||||
*/
|
*/
|
||||||
export function pureFunction2(
|
export function pureFunction2(
|
||||||
pureFn: (v1: any, v2: any) => any, exp1: any, exp2: any, thisArg?: any): any {
|
slotOffset: number, pureFn: (v1: any, v2: any) => any, exp1: any, exp2: any,
|
||||||
return bindingUpdated2(exp1, exp2) ?
|
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)) :
|
checkAndUpdateBinding(thisArg ? pureFn.call(thisArg, exp1, exp2) : pureFn(exp1, exp2)) :
|
||||||
consumeBinding();
|
consumeBinding();
|
||||||
|
restoreBindingIndex(index);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the value of any provided exp has changed, calls the pure function to return
|
* 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.
|
* an updated value. Or if no values have changed, returns cached value.
|
||||||
*
|
*
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param pureFn
|
* @param pureFn
|
||||||
* @param exp1
|
* @param exp1
|
||||||
* @param exp2
|
* @param exp2
|
||||||
* @param exp3
|
* @param exp3
|
||||||
* @param thisArg Optional calling context of pureFn
|
* @param thisArg Optional calling context of pureFn
|
||||||
* @returns Updated value
|
* @returns Updated or cached value
|
||||||
*/
|
*/
|
||||||
export function pureFunction3(
|
export function pureFunction3(
|
||||||
pureFn: (v1: any, v2: any, v3: any) => any, exp1: any, exp2: any, exp3: any,
|
slotOffset: number, pureFn: (v1: any, v2: any, v3: any) => any, exp1: any, exp2: any, exp3: any,
|
||||||
thisArg?: any): any {
|
thisArg?: any): any {
|
||||||
|
ngDevMode && assertReservedSlotInitialized(slotOffset, 4);
|
||||||
|
const index = moveBindingIndexToReservedSlot(slotOffset);
|
||||||
const different = bindingUpdated2(exp1, exp2);
|
const different = bindingUpdated2(exp1, exp2);
|
||||||
return bindingUpdated(exp3) || different ?
|
const value = bindingUpdated(exp3) || different ?
|
||||||
checkAndUpdateBinding(
|
checkAndUpdateBinding(
|
||||||
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3) : pureFn(exp1, exp2, exp3)) :
|
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3) : pureFn(exp1, exp2, exp3)) :
|
||||||
consumeBinding();
|
consumeBinding();
|
||||||
|
restoreBindingIndex(index);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the value of any provided exp has changed, calls the pure function to return
|
* 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.
|
* an updated value. Or if no values have changed, returns cached value.
|
||||||
*
|
*
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param pureFn
|
* @param pureFn
|
||||||
* @param exp1
|
* @param exp1
|
||||||
* @param exp2
|
* @param exp2
|
||||||
* @param exp3
|
* @param exp3
|
||||||
* @param exp4
|
* @param exp4
|
||||||
* @param thisArg Optional calling context of pureFn
|
* @param thisArg Optional calling context of pureFn
|
||||||
* @returns Updated value
|
* @returns Updated or cached value
|
||||||
*/
|
*/
|
||||||
export function pureFunction4(
|
export function pureFunction4(
|
||||||
pureFn: (v1: any, v2: any, v3: any, v4: any) => any, exp1: any, exp2: any, exp3: any, exp4: any,
|
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any) => any, exp1: any, exp2: any,
|
||||||
thisArg?: any): any {
|
exp3: any, exp4: any, thisArg?: any): any {
|
||||||
return bindingUpdated4(exp1, exp2, exp3, exp4) ?
|
ngDevMode && assertReservedSlotInitialized(slotOffset, 5);
|
||||||
|
const index = moveBindingIndexToReservedSlot(slotOffset);
|
||||||
|
const value = bindingUpdated4(exp1, exp2, exp3, exp4) ?
|
||||||
checkAndUpdateBinding(
|
checkAndUpdateBinding(
|
||||||
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4) : pureFn(exp1, exp2, exp3, exp4)) :
|
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4) : pureFn(exp1, exp2, exp3, exp4)) :
|
||||||
consumeBinding();
|
consumeBinding();
|
||||||
|
restoreBindingIndex(index);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the value of any provided exp has changed, calls the pure function to return
|
* 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.
|
* an updated value. Or if no values have changed, returns cached value.
|
||||||
*
|
*
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param pureFn
|
* @param pureFn
|
||||||
* @param exp1
|
* @param exp1
|
||||||
* @param exp2
|
* @param exp2
|
||||||
|
@ -108,23 +137,28 @@ export function pureFunction4(
|
||||||
* @param exp4
|
* @param exp4
|
||||||
* @param exp5
|
* @param exp5
|
||||||
* @param thisArg Optional calling context of pureFn
|
* @param thisArg Optional calling context of pureFn
|
||||||
* @returns Updated value
|
* @returns Updated or cached value
|
||||||
*/
|
*/
|
||||||
export function pureFunction5(
|
export function pureFunction5(
|
||||||
pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any) => any, exp1: any, exp2: any, exp3: any,
|
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any) => any, exp1: any,
|
||||||
exp4: any, exp5: any, thisArg?: any): 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 different = bindingUpdated4(exp1, exp2, exp3, exp4);
|
||||||
return bindingUpdated(exp5) || different ?
|
const value = bindingUpdated(exp5) || different ?
|
||||||
checkAndUpdateBinding(
|
checkAndUpdateBinding(
|
||||||
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) :
|
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5) :
|
||||||
pureFn(exp1, exp2, exp3, exp4, exp5)) :
|
pureFn(exp1, exp2, exp3, exp4, exp5)) :
|
||||||
consumeBinding();
|
consumeBinding();
|
||||||
|
restoreBindingIndex(index);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the value of any provided exp has changed, calls the pure function to return
|
* 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.
|
* an updated value. Or if no values have changed, returns cached value.
|
||||||
*
|
*
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param pureFn
|
* @param pureFn
|
||||||
* @param exp1
|
* @param exp1
|
||||||
* @param exp2
|
* @param exp2
|
||||||
|
@ -133,23 +167,28 @@ export function pureFunction5(
|
||||||
* @param exp5
|
* @param exp5
|
||||||
* @param exp6
|
* @param exp6
|
||||||
* @param thisArg Optional calling context of pureFn
|
* @param thisArg Optional calling context of pureFn
|
||||||
* @returns Updated value
|
* @returns Updated or cached value
|
||||||
*/
|
*/
|
||||||
export function pureFunction6(
|
export function pureFunction6(
|
||||||
pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any) => any, exp1: any, exp2: any,
|
slotOffset: number, pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any) => any,
|
||||||
exp3: any, exp4: any, exp5: any, exp6: any, thisArg?: 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 different = bindingUpdated4(exp1, exp2, exp3, exp4);
|
||||||
return bindingUpdated2(exp5, exp6) || different ?
|
const value = bindingUpdated2(exp5, exp6) || different ?
|
||||||
checkAndUpdateBinding(
|
checkAndUpdateBinding(
|
||||||
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) :
|
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6) :
|
||||||
pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) :
|
pureFn(exp1, exp2, exp3, exp4, exp5, exp6)) :
|
||||||
consumeBinding();
|
consumeBinding();
|
||||||
|
restoreBindingIndex(index);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the value of any provided exp has changed, calls the pure function to return
|
* 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.
|
* an updated value. Or if no values have changed, returns cached value.
|
||||||
*
|
*
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param pureFn
|
* @param pureFn
|
||||||
* @param exp1
|
* @param exp1
|
||||||
* @param exp2
|
* @param exp2
|
||||||
|
@ -159,24 +198,30 @@ export function pureFunction6(
|
||||||
* @param exp6
|
* @param exp6
|
||||||
* @param exp7
|
* @param exp7
|
||||||
* @param thisArg Optional calling context of pureFn
|
* @param thisArg Optional calling context of pureFn
|
||||||
* @returns Updated value
|
* @returns Updated or cached value
|
||||||
*/
|
*/
|
||||||
export function pureFunction7(
|
export function pureFunction7(
|
||||||
|
slotOffset: number,
|
||||||
pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any) => any, exp1: any,
|
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 {
|
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);
|
let different = bindingUpdated4(exp1, exp2, exp3, exp4);
|
||||||
different = bindingUpdated2(exp5, exp6) || different;
|
different = bindingUpdated2(exp5, exp6) || different;
|
||||||
return bindingUpdated(exp7) || different ?
|
const value = bindingUpdated(exp7) || different ?
|
||||||
checkAndUpdateBinding(
|
checkAndUpdateBinding(
|
||||||
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) :
|
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7) :
|
||||||
pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) :
|
pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7)) :
|
||||||
consumeBinding();
|
consumeBinding();
|
||||||
|
restoreBindingIndex(index);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the value of any provided exp has changed, calls the pure function to return
|
* 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.
|
* an updated value. Or if no values have changed, returns cached value.
|
||||||
*
|
*
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param pureFn
|
* @param pureFn
|
||||||
* @param exp1
|
* @param exp1
|
||||||
* @param exp2
|
* @param exp2
|
||||||
|
@ -187,18 +232,23 @@ export function pureFunction7(
|
||||||
* @param exp7
|
* @param exp7
|
||||||
* @param exp8
|
* @param exp8
|
||||||
* @param thisArg Optional calling context of pureFn
|
* @param thisArg Optional calling context of pureFn
|
||||||
* @returns Updated value
|
* @returns Updated or cached value
|
||||||
*/
|
*/
|
||||||
export function pureFunction8(
|
export function pureFunction8(
|
||||||
|
slotOffset: number,
|
||||||
pureFn: (v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any, v8: any) => any,
|
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,
|
exp1: any, exp2: any, exp3: any, exp4: any, exp5: any, exp6: any, exp7: any, exp8: any,
|
||||||
thisArg?: any): any {
|
thisArg?: any): any {
|
||||||
|
ngDevMode && assertReservedSlotInitialized(slotOffset, 9);
|
||||||
|
const index = moveBindingIndexToReservedSlot(slotOffset);
|
||||||
const different = bindingUpdated4(exp1, exp2, exp3, exp4);
|
const different = bindingUpdated4(exp1, exp2, exp3, exp4);
|
||||||
return bindingUpdated4(exp5, exp6, exp7, exp8) || different ?
|
const value = bindingUpdated4(exp5, exp6, exp7, exp8) || different ?
|
||||||
checkAndUpdateBinding(
|
checkAndUpdateBinding(
|
||||||
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) :
|
thisArg ? pureFn.call(thisArg, exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8) :
|
||||||
pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) :
|
pureFn(exp1, exp2, exp3, exp4, exp5, exp6, exp7, exp8)) :
|
||||||
consumeBinding();
|
consumeBinding();
|
||||||
|
restoreBindingIndex(index);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -207,17 +257,23 @@ export function pureFunction8(
|
||||||
* If the value of any provided exp has changed, calls the pure function to return
|
* 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.
|
* an updated value. Or if no values have changed, returns cached value.
|
||||||
*
|
*
|
||||||
|
* @param slotOffset the offset in the reserved slot space {@link reserveSlots}
|
||||||
* @param pureFn A pure function that takes binding values and builds an object or array
|
* @param pureFn A pure function that takes binding values and builds an object or array
|
||||||
* containing those values.
|
* containing those values.
|
||||||
* @param exps An array of binding values
|
* @param exps An array of binding values
|
||||||
* @param thisArg Optional calling context of pureFn
|
* @param thisArg Optional calling context of pureFn
|
||||||
* @returns Updated value
|
* @returns Updated or cached value
|
||||||
*/
|
*/
|
||||||
export function pureFunctionV(pureFn: (...v: any[]) => any, exps: any[], thisArg?: any): any {
|
export function pureFunctionV(
|
||||||
let different = false;
|
slotOffset: number, pureFn: (...v: any[]) => any, exps: any[], thisArg?: any): any {
|
||||||
|
ngDevMode && assertReservedSlotInitialized(slotOffset, exps.length + 1);
|
||||||
|
const index = moveBindingIndexToReservedSlot(slotOffset);
|
||||||
|
|
||||||
|
let different = false;
|
||||||
for (let i = 0; i < exps.length; i++) {
|
for (let i = 0; i < exps.length; i++) {
|
||||||
bindingUpdated(exps[i]) && (different = true);
|
bindingUpdated(exps[i]) && (different = true);
|
||||||
}
|
}
|
||||||
return different ? checkAndUpdateBinding(pureFn.apply(thisArg, exps)) : consumeBinding();
|
const value = different ? checkAndUpdateBinding(pureFn.apply(thisArg, exps)) : consumeBinding();
|
||||||
|
restoreBindingIndex(index);
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -502,9 +502,10 @@ describe('components & directives', () => {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-array-comp');
|
$r3$.ɵE(0, 'my-array-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(0, 'names', $r3$.ɵb(ctx.someFn($r3$.ɵf0($e0_ff$))));
|
$r3$.ɵp(0, 'names', $r3$.ɵb(ctx.someFn($r3$.ɵf0(1, $e0_ff$))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -563,9 +564,10 @@ describe('components & directives', () => {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-comp');
|
$r3$.ɵE(0, 'my-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(1);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(0, 'num', $r3$.ɵb($r3$.ɵf0($e0_ff$).length + 1));
|
$r3$.ɵp(0, 'num', $r3$.ɵb($r3$.ɵf0(1, $e0_ff$).length + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -606,9 +608,10 @@ describe('components & directives', () => {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-array-comp');
|
$r3$.ɵE(0, 'my-array-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(2);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(0, 'names', $r3$.ɵb($r3$.ɵf1($e0_ff$, ctx.customName)));
|
$r3$.ɵp(0, 'names', $r3$.ɵb($r3$.ɵf1(2, $e0_ff$, ctx.customName)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -716,12 +719,13 @@ describe('components & directives', () => {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'my-comp');
|
$r3$.ɵE(0, 'my-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(10);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(
|
$r3$.ɵp(
|
||||||
0, 'names',
|
0, 'names',
|
||||||
$r3$.ɵb(
|
$r3$.ɵb($r3$.ɵfV(
|
||||||
$r3$.ɵfV($e0_ff$, [c.n0, c.n1, c.n2, c.n3, c.n4, c.n5, c.n6, c.n7, c.n8])));
|
10, $e0_ff$, [c.n0, c.n1, c.n2, c.n3, c.n4, c.n5, c.n6, c.n7, c.n8])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -794,9 +798,10 @@ describe('components & directives', () => {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'object-comp');
|
$r3$.ɵE(0, 'object-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(2);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(0, 'config', $r3$.ɵb($r3$.ɵf1($e0_ff$, ctx.name)));
|
$r3$.ɵp(0, 'config', $r3$.ɵb($r3$.ɵf1(2, $e0_ff$, ctx.name)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -879,12 +884,13 @@ describe('components & directives', () => {
|
||||||
if (rf & 1) {
|
if (rf & 1) {
|
||||||
$r3$.ɵE(0, 'nested-comp');
|
$r3$.ɵE(0, 'nested-comp');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(7);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵp(
|
$r3$.ɵp(
|
||||||
0, 'config', $r3$.ɵf2(
|
0, 'config', $r3$.ɵb($r3$.ɵf2(
|
||||||
$e0_ff_2$, ctx.name,
|
7, $e0_ff_2$, ctx.name,
|
||||||
$r3$.ɵb($r3$.ɵf1($e0_ff_1$, $r3$.ɵf1($e0_ff$, ctx.duration)))));
|
$r3$.ɵf1(4, $e0_ff_1$, $r3$.ɵf1(2, $e0_ff$, ctx.duration)))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -88,9 +88,12 @@ describe('pipes', () => {
|
||||||
$r3$.ɵT(0);
|
$r3$.ɵT(0);
|
||||||
$r3$.ɵPp(1, 'myPipe');
|
$r3$.ɵPp(1, 'myPipe');
|
||||||
$r3$.ɵPp(2, 'myPurePipe');
|
$r3$.ɵPp(2, 'myPurePipe');
|
||||||
|
$r3$.ɵrS(6);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵt(0, $r3$.ɵi1('', $r3$.ɵpb2(1, $r3$.ɵpb2(2, ctx.name, ctx.size), ctx.size), ''));
|
$r3$.ɵt(
|
||||||
|
0,
|
||||||
|
$r3$.ɵi1('', $r3$.ɵpb2(1, 6, $r3$.ɵpb2(2, 3, ctx.name, ctx.size), ctx.size), ''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -166,10 +169,11 @@ describe('pipes', () => {
|
||||||
$r3$.ɵT(2);
|
$r3$.ɵT(2);
|
||||||
$r3$.ɵPp(3, 'myPurePipe');
|
$r3$.ɵPp(3, 'myPurePipe');
|
||||||
$r3$.ɵC(4, C4, '', ['oneTimeIf', '']);
|
$r3$.ɵC(4, C4, '', ['oneTimeIf', '']);
|
||||||
|
$r3$.ɵrS(6);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵt(0, $r3$.ɵi1('', $r3$.ɵpb2(1, ctx.name, ctx.size), ''));
|
$r3$.ɵt(0, $r3$.ɵi1('', $r3$.ɵpb2(1, 3, ctx.name, ctx.size), ''));
|
||||||
$r3$.ɵt(2, $r3$.ɵi1('', $r3$.ɵpb2(3, ctx.name, ctx.size), ''));
|
$r3$.ɵt(2, $r3$.ɵi1('', $r3$.ɵpb2(3, 6, ctx.name, ctx.size), ''));
|
||||||
$r3$.ɵp(4, 'oneTimeIf', $r3$.ɵb(ctx.more));
|
$r3$.ɵp(4, 'oneTimeIf', $r3$.ɵb(ctx.more));
|
||||||
$r3$.ɵcR(4);
|
$r3$.ɵcR(4);
|
||||||
$r3$.ɵcr();
|
$r3$.ɵcr();
|
||||||
|
@ -181,9 +185,10 @@ describe('pipes', () => {
|
||||||
$r3$.ɵT(1);
|
$r3$.ɵT(1);
|
||||||
$r3$.ɵPp(2, 'myPurePipe');
|
$r3$.ɵPp(2, 'myPurePipe');
|
||||||
$r3$.ɵe();
|
$r3$.ɵe();
|
||||||
|
$r3$.ɵrS(3);
|
||||||
}
|
}
|
||||||
if (rf & 2) {
|
if (rf & 2) {
|
||||||
$r3$.ɵt(1, $r3$.ɵi1('', $r3$.ɵpb2(2, ctx.name, ctx.size), ''));
|
$r3$.ɵt(1, $r3$.ɵi1('', $r3$.ɵpb2(2, 3, ctx.name, ctx.size), ''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {Directive, OnChanges, OnDestroy, Pipe, PipeTransform} from '@angular/cor
|
||||||
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
import {expect} from '@angular/platform-browser/testing/src/matchers';
|
||||||
|
|
||||||
import {defineDirective, definePipe} from '../../src/render3/definition';
|
import {defineDirective, definePipe} from '../../src/render3/definition';
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, text, textBinding} from '../../src/render3/instructions';
|
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, reserveSlots, text, textBinding} from '../../src/render3/instructions';
|
||||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
import {pipe, pipeBind1, pipeBind3, pipeBind4, pipeBindV} from '../../src/render3/pipe';
|
import {pipe, pipeBind1, pipeBind3, pipeBind4, pipeBindV} from '../../src/render3/pipe';
|
||||||
|
|
||||||
|
@ -38,9 +38,10 @@ describe('pipe', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
text(0);
|
text(0);
|
||||||
pipe(1, 'countingPipe');
|
pipe(1, 'countingPipe');
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
textBinding(0, interpolation1('', pipeBind1(1, person.name), ''));
|
textBinding(0, interpolation1('', pipeBind1(1, 2, person.name), ''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,9 +54,10 @@ describe('pipe', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
text(0);
|
text(0);
|
||||||
pipe(1, 'randomPipeName');
|
pipe(1, 'randomPipeName');
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
textBinding(0, interpolation1('', pipeBind1(1, ctx.value), ''));
|
textBinding(0, interpolation1('', pipeBind1(1, 2, ctx.value), ''));
|
||||||
}
|
}
|
||||||
}, [], pipes);
|
}, [], pipes);
|
||||||
|
|
||||||
|
@ -97,9 +99,10 @@ describe('pipe', () => {
|
||||||
elementStart(0, 'div', ['myDir', '']);
|
elementStart(0, 'div', ['myDir', '']);
|
||||||
pipe(1, 'double');
|
pipe(1, 'double');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(0, 'elprop', bind(pipeBind1(1, ctx)));
|
elementProperty(0, 'elprop', bind(pipeBind1(1, 2, ctx)));
|
||||||
directive = loadDirective(0);
|
directive = loadDirective(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,10 +115,11 @@ describe('pipe', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
text(0);
|
text(0);
|
||||||
pipe(1, 'multiArgPipe');
|
pipe(1, 'multiArgPipe');
|
||||||
|
reserveSlots(4);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
textBinding(
|
textBinding(
|
||||||
0, interpolation1('', pipeBind3(1, person.name, 'one', person.address !.city), ''));
|
0, interpolation1('', pipeBind3(1, 4, person.name, 'one', person.address !.city), ''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,11 +133,12 @@ describe('pipe', () => {
|
||||||
text(0);
|
text(0);
|
||||||
pipe(1, 'multiArgPipe');
|
pipe(1, 'multiArgPipe');
|
||||||
pipe(2, 'multiArgPipe');
|
pipe(2, 'multiArgPipe');
|
||||||
|
reserveSlots(9);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
textBinding(
|
textBinding(
|
||||||
0,
|
0, interpolation1(
|
||||||
interpolation1('', pipeBind4(2, pipeBindV(1, [person.name, 'a', 'b']), 0, 1, 2), ''));
|
'', pipeBind4(2, 9, pipeBindV(1, 4, [person.name, 'a', 'b']), 0, 1, 2), ''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,9 +163,10 @@ describe('pipe', () => {
|
||||||
elementStart(0, 'div');
|
elementStart(0, 'div');
|
||||||
pipe(1, 'identityPipe');
|
pipe(1, 'identityPipe');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(0, 'someProp', bind(pipeBind1(1, 'Megatron')));
|
elementProperty(0, 'someProp', bind(pipeBind1(1, 2, 'Megatron')));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,9 +184,10 @@ describe('pipe', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
text(0);
|
text(0);
|
||||||
pipe(1, 'countingPipe');
|
pipe(1, 'countingPipe');
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
textBinding(0, interpolation1('', pipeBind1(1, person.name), ''));
|
textBinding(0, interpolation1('', pipeBind1(1, 2, person.name), ''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,9 +214,10 @@ describe('pipe', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
text(0);
|
text(0);
|
||||||
pipe(1, 'countingImpurePipe');
|
pipe(1, 'countingImpurePipe');
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
textBinding(0, interpolation1('', pipeBind1(1, person.name), ''));
|
textBinding(0, interpolation1('', pipeBind1(1, 2, person.name), ''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,10 +236,11 @@ describe('pipe', () => {
|
||||||
pipe(3, 'countingImpurePipe');
|
pipe(3, 'countingImpurePipe');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
container(4);
|
container(4);
|
||||||
|
reserveSlots(4);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(0, 'someProp', bind(pipeBind1(1, true)));
|
elementProperty(0, 'someProp', bind(pipeBind1(1, 2, true)));
|
||||||
elementProperty(2, 'someProp', bind(pipeBind1(3, true)));
|
elementProperty(2, 'someProp', bind(pipeBind1(3, 4, true)));
|
||||||
pipeInstances.push(load<CountingImpurePipe>(1), load(3));
|
pipeInstances.push(load<CountingImpurePipe>(1), load(3));
|
||||||
containerRefreshStart(4);
|
containerRefreshStart(4);
|
||||||
{
|
{
|
||||||
|
@ -242,9 +251,10 @@ describe('pipe', () => {
|
||||||
elementStart(0, 'div');
|
elementStart(0, 'div');
|
||||||
pipe(1, 'countingImpurePipe');
|
pipe(1, 'countingImpurePipe');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf1 & RenderFlags.Update) {
|
if (rf1 & RenderFlags.Update) {
|
||||||
elementProperty(0, 'someProp', bind(pipeBind1(1, true)));
|
elementProperty(0, 'someProp', bind(pipeBind1(1, 2, true)));
|
||||||
pipeInstances.push(load<CountingImpurePipe>(1));
|
pipeInstances.push(load<CountingImpurePipe>(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,9 +306,10 @@ describe('pipe', () => {
|
||||||
if (rf1 & RenderFlags.Create) {
|
if (rf1 & RenderFlags.Create) {
|
||||||
text(0);
|
text(0);
|
||||||
pipe(1, 'pipeWithOnDestroy');
|
pipe(1, 'pipeWithOnDestroy');
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
textBinding(0, interpolation1('', pipeBind1(1, person.age), ''));
|
textBinding(0, interpolation1('', pipeBind1(1, 2, person.age), ''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
embeddedViewEnd();
|
embeddedViewEnd();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
import {defineComponent} from '../../src/render3/index';
|
import {defineComponent} from '../../src/render3/index';
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective} from '../../src/render3/instructions';
|
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, reserveSlots} from '../../src/render3/instructions';
|
||||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunction5, pureFunction6, pureFunction7, pureFunction8, pureFunctionV} from '../../src/render3/pure_function';
|
import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunction5, pureFunction6, pureFunction7, pureFunction8, pureFunctionV} from '../../src/render3/pure_function';
|
||||||
import {renderToHtml} from '../../test/render3/render_util';
|
import {renderToHtml} from '../../test/render3/render_util';
|
||||||
|
@ -36,9 +36,10 @@ describe('array literals', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
elementStart(0, 'my-comp');
|
elementStart(0, 'my-comp');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(0, 'names', bind(pureFunction1(e0_ff, ctx.customName)));
|
elementProperty(0, 'names', bind(pureFunction1(2, e0_ff, ctx.customName)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,10 +91,11 @@ describe('array literals', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
elementStart(0, 'many-prop-comp');
|
elementStart(0, 'many-prop-comp');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(4);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(0, 'names1', bind(pureFunction1(e0_ff, ctx.customName)));
|
elementProperty(0, 'names1', bind(pureFunction1(2, e0_ff, ctx.customName)));
|
||||||
elementProperty(0, 'names2', bind(pureFunction1(e0_ff_1, ctx.customName2)));
|
elementProperty(0, 'names2', bind(pureFunction1(4, e0_ff_1, ctx.customName2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,9 +132,10 @@ describe('array literals', () => {
|
||||||
elementStart(0, 'my-comp');
|
elementStart(0, 'my-comp');
|
||||||
myComps.push(loadDirective(0));
|
myComps.push(loadDirective(0));
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(0, 'names', bind(ctx.someFn(pureFunction1(e0_ff, ctx.customName))));
|
elementProperty(0, 'names', bind(ctx.someFn(pureFunction1(2, e0_ff, ctx.customName))));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directives: directives
|
directives: directives
|
||||||
|
@ -170,9 +173,10 @@ describe('array literals', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
elementStart(0, 'my-comp');
|
elementStart(0, 'my-comp');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(3);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(0, 'names', bind(pureFunction2(e0_ff, ctx.customName, ctx.customName2)));
|
elementProperty(0, 'names', bind(pureFunction2(3, e0_ff, ctx.customName, ctx.customName2)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,17 +245,19 @@ describe('array literals', () => {
|
||||||
elementStart(5, 'my-comp');
|
elementStart(5, 'my-comp');
|
||||||
f8Comp = loadDirective(5);
|
f8Comp = loadDirective(5);
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(39);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(0, 'names', bind(pureFunction3(e0_ff, c[5], c[6], c[7])));
|
elementProperty(0, 'names', bind(pureFunction3(4, e0_ff, c[5], c[6], c[7])));
|
||||||
elementProperty(1, 'names', bind(pureFunction4(e2_ff, c[4], c[5], c[6], c[7])));
|
elementProperty(1, 'names', bind(pureFunction4(9, e2_ff, c[4], c[5], c[6], c[7])));
|
||||||
elementProperty(2, 'names', bind(pureFunction5(e4_ff, c[3], 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(e6_ff, c[2], c[3], c[4], c[5], c[6], c[7])));
|
|
||||||
elementProperty(
|
elementProperty(
|
||||||
4, 'names', bind(pureFunction7(e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
|
3, 'names', bind(pureFunction6(22, 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])));
|
||||||
elementProperty(
|
elementProperty(
|
||||||
5, 'names',
|
5, 'names',
|
||||||
bind(pureFunction8(e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
|
bind(pureFunction8(39, e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,11 +301,12 @@ describe('array literals', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
elementStart(0, 'my-comp');
|
elementStart(0, 'my-comp');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(12);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(
|
elementProperty(
|
||||||
0, 'names', bind(pureFunctionV(e0_ff, [
|
0, 'names', bind(pureFunctionV(12, e0_ff, [
|
||||||
c[0], c[1], c[2], c[3], pureFunction1(e0_ff_1, c[4]), c[5], c[6], c[7], c[8]
|
c[0], c[1], c[2], c[3], pureFunction1(2, e0_ff_1, c[4]), c[5], c[6], c[7], c[8]
|
||||||
])));
|
])));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,9 +352,10 @@ describe('object literals', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
elementStart(0, 'object-comp');
|
elementStart(0, 'object-comp');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(0, 'config', bind(pureFunction1(e0_ff, ctx.name)));
|
elementProperty(0, 'config', bind(pureFunction1(2, e0_ff, ctx.name)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,12 +388,13 @@ describe('object literals', () => {
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Create) {
|
||||||
elementStart(0, 'object-comp');
|
elementStart(0, 'object-comp');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(7);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(
|
elementProperty(
|
||||||
0, 'config',
|
0, 'config', bind(pureFunction2(
|
||||||
bind(pureFunction2(
|
7, e0_ff, ctx.name,
|
||||||
e0_ff, ctx.name, pureFunction1(e0_ff_1, pureFunction1(e0_ff_2, ctx.duration)))));
|
pureFunction1(4, e0_ff_1, pureFunction1(2, e0_ff_2, ctx.duration)))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,11 +460,12 @@ describe('object literals', () => {
|
||||||
elementStart(0, 'object-comp');
|
elementStart(0, 'object-comp');
|
||||||
objectComps.push(loadDirective(0));
|
objectComps.push(loadDirective(0));
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(3);
|
||||||
}
|
}
|
||||||
if (rf1 & RenderFlags.Update) {
|
if (rf1 & RenderFlags.Update) {
|
||||||
elementProperty(
|
elementProperty(
|
||||||
0, 'config',
|
0, 'config',
|
||||||
bind(pureFunction2(e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration)));
|
bind(pureFunction2(3, e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration)));
|
||||||
}
|
}
|
||||||
embeddedViewEnd();
|
embeddedViewEnd();
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
import {Component, Directive, Pipe, PipeTransform, TemplateRef, ViewContainerRef} from '../../src/core';
|
import {Component, Directive, Pipe, PipeTransform, TemplateRef, ViewContainerRef} from '../../src/core';
|
||||||
import {getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from '../../src/render3/di';
|
import {getOrCreateNodeInjectorForNode, getOrCreateTemplateRef} from '../../src/render3/di';
|
||||||
import {NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
import {NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
|
||||||
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, projection, projectionDef, text, textBinding} from '../../src/render3/instructions';
|
import {bind, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, load, loadDirective, projection, projectionDef, reserveSlots, text, textBinding} from '../../src/render3/instructions';
|
||||||
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
import {RenderFlags} from '../../src/render3/interfaces/definition';
|
||||||
import {pipe, pipeBind1} from '../../src/render3/pipe';
|
import {pipe, pipeBind1} from '../../src/render3/pipe';
|
||||||
|
|
||||||
|
@ -383,22 +383,25 @@ describe('ViewContainerRef', () => {
|
||||||
elementStart(0, 'child');
|
elementStart(0, 'child');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
pipe(1, 'starPipe');
|
pipe(1, 'starPipe');
|
||||||
|
reserveSlots(2);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Create) {
|
if (rf & RenderFlags.Update) {
|
||||||
elementProperty(0, 'name', bind(pipeBind1(1, 'C')));
|
elementProperty(0, 'name', bind(pipeBind1(1, 2, 'C')));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
pipe(1, 'starPipe');
|
pipe(1, 'starPipe');
|
||||||
elementStart(2, 'child', ['vcref', '']);
|
elementStart(2, 'child', ['vcref', '']);
|
||||||
elementEnd();
|
elementEnd();
|
||||||
elementStart(3, 'child');
|
pipe(3, 'starPipe');
|
||||||
|
elementStart(4, 'child');
|
||||||
elementEnd();
|
elementEnd();
|
||||||
|
reserveSlots(4);
|
||||||
}
|
}
|
||||||
if (rf & RenderFlags.Update) {
|
if (rf & RenderFlags.Update) {
|
||||||
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
|
const tplRef = getOrCreateTemplateRef(getOrCreateNodeInjectorForNode(load(0)));
|
||||||
elementProperty(2, 'tplRef', bind(tplRef));
|
elementProperty(2, 'tplRef', bind(tplRef));
|
||||||
elementProperty(2, 'name', bind(pipeBind1(1, 'A')));
|
elementProperty(2, 'name', bind(pipeBind1(1, 2, 'A')));
|
||||||
elementProperty(3, 'name', bind(pipeBind1(1, 'B')));
|
elementProperty(4, 'name', bind(pipeBind1(1, 4, 'B')));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
directives: [Child, DirectiveWithVCRef],
|
directives: [Child, DirectiveWithVCRef],
|
||||||
|
|
Loading…
Reference in New Issue