feat(ivy): add pureFunction0 instruction (#22214)

PR Close #22214
This commit is contained in:
Kara Erickson
2018-02-14 13:37:54 -08:00
committed by Victor Berchet
parent a73d5308e0
commit f693be3996
7 changed files with 353 additions and 241 deletions

View File

@ -209,7 +209,7 @@ describe('compiler specification', () => {
if (cm) {
$r3$.ɵT(0);
}
$r3$.ɵt(0, $r3$.ɵb2('', ctx.names[0], ' ', ctx.names[1], ''));
$r3$.ɵt(0, $r3$.ɵi2('', ctx.names[0], ' ', ctx.names[1], ''));
},
inputs: {names: 'names'}
});
@ -239,7 +239,7 @@ describe('compiler specification', () => {
$r3$.ɵE(0, MyArrayComp);
$r3$.ɵe();
}
$r3$.ɵp(0, 'names', $r3$.ɵb0($e0_arr$));
$r3$.ɵp(0, 'names', cm ? $e0_arr$ : $r3$.ɵNC);
MyArrayComp.ngComponentDef.h(1, 0);
$r3$.ɵr(1, 0);
}
@ -250,6 +250,101 @@ describe('compiler specification', () => {
expect(renderComp(MyApp)).toEqual(`<my-array-comp>Nancy Bess</my-array-comp>`);
});
it('should support array literals of constants inside function calls', () => {
type $MyApp$ = MyApp;
// NORMATIVE
const $e0_ff$ = () => ['Nancy', 'Bess'];
// /NORMATIVE
@Component({
selector: 'my-app',
template: `
<my-array-comp [names]="someFn(['Nancy', 'Bess'])"></my-array-comp>
`
})
class MyApp {
someFn(arr: string[]): string[] {
arr[0] = arr[0].toUpperCase();
return arr;
}
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
tag: 'my-app',
factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) {
if (cm) {
$r3$.ɵE(0, MyArrayComp);
$r3$.ɵe();
}
$r3$.ɵp(0, 'names', $r3$.ɵb(ctx.someFn($r3$.ɵf0($e0_ff$))));
MyArrayComp.ngComponentDef.h(1, 0);
$r3$.ɵr(1, 0);
}
});
// /NORMATIVE
}
expect(renderComp(MyApp)).toEqual(`<my-array-comp>NANCY Bess</my-array-comp>`);
});
it('should support array literals of constants inside expressions', () => {
type $MyApp$ = MyApp;
type $MyComp$ = MyComp;
@Component({selector: 'my-comp', template: `{{ num }}`})
class MyComp {
num: number;
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyComp,
tag: 'my-comp',
factory: function MyComp_Factory() { return new MyComp(); },
template: function MyComp_Template(ctx: $MyComp$, cm: $boolean$) {
if (cm) {
$r3$.ɵT(0);
}
$r3$.ɵt(0, $r3$.ɵb(ctx.num));
},
inputs: {num: 'num'}
});
}
// NORMATIVE
const $e0_ff$ = () => ['Nancy', 'Bess'];
// /NORMATIVE
@Component({
selector: 'my-app',
template: `
<my-comp [num]="['Nancy', 'Bess'].length + 1"></my-comp>
`
})
class MyApp {
// NORMATIVE
static ngComponentDef = $r3$.ɵdefineComponent({
type: MyApp,
tag: 'my-app',
factory: function MyApp_Factory() { return new MyApp(); },
template: function MyApp_Template(ctx: $MyApp$, cm: $boolean$) {
if (cm) {
$r3$.ɵE(0, MyComp);
$r3$.ɵe();
}
$r3$.ɵp(0, 'num', $r3$.ɵb($r3$.ɵf0($e0_ff$).length + 1));
MyComp.ngComponentDef.h(1, 0);
$r3$.ɵr(1, 0);
}
});
// /NORMATIVE
}
expect(renderComp(MyApp)).toEqual(`<my-comp>3</my-comp>`);
});
it('should support array literals', () => {
type $MyApp$ = MyApp;
@ -276,7 +371,7 @@ describe('compiler specification', () => {
$r3$.ɵE(0, MyArrayComp);
$r3$.ɵe();
}
$r3$.ɵp(0, 'names', $r3$.ɵf1($e0_ff$, ctx.customName));
$r3$.ɵp(0, 'names', $r3$.ɵb($r3$.ɵf1($e0_ff$, ctx.customName)));
MyArrayComp.ngComponentDef.h(1, 0);
$r3$.ɵr(1, 0);
}
@ -346,8 +441,9 @@ describe('compiler specification', () => {
}
// NORMATIVE
const $e0_ff$ = (v: any[]) =>
['start-', v[0], v[1], v[2], v[3], v[4], '-middle-', v[5], v[6], v[7], v[8], '-end'];
const $e0_ff$ =
(v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any,
v8: any) => ['start-', v0, v1, v2, v3, v4, '-middle-', v5, v6, v7, v8, '-end'];
// /NORMATIVE
@Component({
@ -380,7 +476,8 @@ describe('compiler specification', () => {
}
$r3$.ɵp(
0, 'names',
$r3$.ɵfV($e0_ff$, [c.n0, c.n1, c.n2, c.n3, c.n4, c.n5, c.n6, c.n7, c.n8]));
$r3$.ɵb(
$r3$.ɵfV($e0_ff$, [c.n0, c.n1, c.n2, c.n3, c.n4, c.n5, c.n6, c.n7, c.n8])));
MyComp.ngComponentDef.h(1, 0);
$r3$.ɵr(1, 0);
}
@ -448,7 +545,7 @@ describe('compiler specification', () => {
$r3$.ɵE(0, ObjectComp);
$r3$.ɵe();
}
$r3$.ɵp(0, 'config', $r3$.ɵf1($e0_ff$, ctx.name));
$r3$.ɵp(0, 'config', $r3$.ɵb($r3$.ɵf1($e0_ff$, ctx.name)));
ObjectComp.ngComponentDef.h(1, 0);
$r3$.ɵr(1, 0);
}
@ -527,9 +624,9 @@ describe('compiler specification', () => {
$r3$.ɵe();
}
$r3$.ɵp(
0, 'config',
$r3$.ɵf2(
$e0_ff_2$, ctx.name, $r3$.ɵf1($e0_ff_1$, $r3$.ɵf1($e0_ff$, ctx.duration))));
0, 'config', $r3$.ɵf2(
$e0_ff_2$, ctx.name,
$r3$.ɵb($r3$.ɵf1($e0_ff_1$, $r3$.ɵf1($e0_ff$, ctx.duration)))));
NestedComp.ngComponentDef.h(1, 0);
$r3$.ɵr(1, 0);
}

View File

@ -72,7 +72,7 @@ describe('render3 integration test', () => {
if (cm) {
text(0);
}
textBinding(0, bind0(value));
textBinding(0, cm ? value : NO_CHANGE);
}
expect(renderToHtml(Template, 'once')).toEqual('once');
expect(renderToHtml(Template, 'twice')).toEqual('once');

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {defineComponent} from '../../src/render3/index';
import {componentRefresh, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, memory} from '../../src/render3/instructions';
import {bind, componentRefresh, container, containerRefreshEnd, containerRefreshStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, memory} from '../../src/render3/instructions';
import {pureFunction1, pureFunction2, pureFunction3, pureFunction4, pureFunction5, pureFunction6, pureFunction7, pureFunction8, pureFunctionV} from '../../src/render3/pure_function';
import {renderToHtml} from '../../test/render3/render_util';
@ -26,19 +26,19 @@ describe('array literals', () => {
}
it('should support an array literal with a binding', () => {
const e0_ff = (v: any) => ['Nancy', v, 'Bess'];
/** <my-comp [names]="['Nancy', customName, 'Bess']"></my-comp> */
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, MyComp);
elementEnd();
}
elementProperty(0, 'names', pureFunction1(e0_ff, ctx.customName));
elementProperty(0, 'names', bind(pureFunction1(e0_ff, ctx.customName)));
MyComp.ngComponentDef.h(1, 0);
componentRefresh(1, 0);
}
const e0_ff = (v: any) => ['Nancy', v, 'Bess'];
renderToHtml(Template, {customName: 'Carson'});
const firstArray = myComp !.names;
expect(firstArray).toEqual(['Nancy', 'Carson', 'Bess']);
@ -52,6 +52,12 @@ describe('array literals', () => {
// Identity must change if binding changes
expect(firstArray).not.toBe(myComp !.names);
// The property should not be set if the exp value is the same, so artificially
// setting the property to ensure it's not overwritten.
myComp !.names = ['should not be overwritten'];
renderToHtml(Template, {customName: 'Hannah'});
expect(myComp !.names).toEqual(['should not be overwritten']);
});
it('should support multiple array literals passed through to one node', () => {
@ -70,6 +76,9 @@ describe('array literals', () => {
});
}
const e0_ff = (v: any) => ['Nancy', v];
const e0_ff_1 = (v: any) => [v];
/**
* <many-prop-comp [names1]="['Nancy', customName]" [names2]="[customName2]">
* </many-prop-comp>
@ -79,15 +88,12 @@ describe('array literals', () => {
elementStart(0, ManyPropComp);
elementEnd();
}
elementProperty(0, 'names1', pureFunction1(e0_ff, ctx.customName));
elementProperty(0, 'names2', pureFunction1(e0_ff_1, ctx.customName2));
elementProperty(0, 'names1', bind(pureFunction1(e0_ff, ctx.customName)));
elementProperty(0, 'names2', bind(pureFunction1(e0_ff_1, ctx.customName2)));
ManyPropComp.ngComponentDef.h(1, 0);
componentRefresh(1, 0);
}
const e0_ff = (v: any) => ['Nancy', v];
const e0_ff_1 = (v: any) => [v];
renderToHtml(Template, {customName: 'Carson', customName2: 'George'});
expect(manyPropComp !.names1).toEqual(['Nancy', 'Carson']);
expect(manyPropComp !.names2).toEqual(['George']);
@ -97,21 +103,78 @@ describe('array literals', () => {
expect(manyPropComp !.names2).toEqual(['Carson']);
});
it('should support an array literals inside fn calls', () => {
let myComps: MyComp[] = [];
const e0_ff = (v: any) => ['Nancy', v];
/** <my-comp [names]="someFn(['Nancy', customName])"></my-comp> */
class ParentComp {
customName = 'Bess';
someFn(arr: string[]): string[] {
arr[0] = arr[0].toUpperCase();
return arr;
}
static ngComponentDef = defineComponent({
type: ParentComp,
tag: 'parent-comp',
factory: () => new ParentComp(),
template: function(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, MyComp);
myComps.push(memory(1));
elementEnd();
}
elementProperty(0, 'names', bind(ctx.someFn(pureFunction1(e0_ff, ctx.customName))));
MyComp.ngComponentDef.h(1, 0);
componentRefresh(1, 0);
}
});
}
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, ParentComp);
elementEnd();
elementStart(2, ParentComp);
elementEnd();
}
ParentComp.ngComponentDef.h(1, 0);
ParentComp.ngComponentDef.h(3, 2);
componentRefresh(1, 0);
componentRefresh(3, 2);
}
renderToHtml(Template, {});
const firstArray = myComps[0].names;
const secondArray = myComps[1].names;
expect(firstArray).toEqual(['NANCY', 'Bess']);
expect(secondArray).toEqual(['NANCY', 'Bess']);
expect(firstArray).not.toBe(secondArray);
renderToHtml(Template, {});
expect(firstArray).toEqual(['NANCY', 'Bess']);
expect(secondArray).toEqual(['NANCY', 'Bess']);
expect(firstArray).toBe(myComps[0].names);
expect(secondArray).toBe(myComps[1].names);
});
it('should support an array literal with more than 1 binding', () => {
const e0_ff = (v1: any, v2: any) => ['Nancy', v1, 'Bess', v2];
/** <my-comp [names]="['Nancy', customName, 'Bess', customName2]"></my-comp> */
function Template(ctx: any, cm: boolean) {
if (cm) {
elementStart(0, MyComp);
elementEnd();
}
elementProperty(0, 'names', pureFunction2(e0_ff, ctx.customName, ctx.customName2));
elementProperty(0, 'names', bind(pureFunction2(e0_ff, ctx.customName, ctx.customName2)));
MyComp.ngComponentDef.h(1, 0);
componentRefresh(1, 0);
}
const e0_ff = (v1: any, v2: any) => ['Nancy', v1, 'Bess', v2];
renderToHtml(Template, {customName: 'Carson', customName2: 'Hannah'});
const firstArray = myComp !.names;
expect(firstArray).toEqual(['Nancy', 'Carson', 'Bess', 'Hannah']);
@ -126,6 +189,12 @@ describe('array literals', () => {
renderToHtml(Template, {customName: 'Frank', customName2: 'Ned'});
expect(myComp !.names).toEqual(['Nancy', 'Frank', 'Bess', 'Ned']);
// The property should not be set if the exp value is the same, so artificially
// setting the property to ensure it's not overwritten.
myComp !.names = ['should not be overwritten'];
renderToHtml(Template, {customName: 'Frank', customName2: 'Ned'});
expect(myComp !.names).toEqual(['should not be overwritten']);
});
it('should work up to 8 bindings', () => {
@ -136,6 +205,21 @@ describe('array literals', () => {
let f7Comp: MyComp;
let f8Comp: MyComp;
const e0_ff = (v1: any, v2: any, v3: any) => ['a', 'b', 'c', 'd', 'e', v1, v2, v3];
const e2_ff = (v1: any, v2: any, v3: any, v4: any) => ['a', 'b', 'c', 'd', v1, v2, v3, v4];
const e4_ff =
(v1: any, v2: any, v3: any, v4: any, v5: any) => ['a', 'b', 'c', v1, v2, v3, v4, v5];
const e6_ff =
(v1: any, v2: any, v3: any, v4: any, v5: any,
v6: any) => ['a', 'b', v1, v2, v3, v4, v5, v6];
const e8_ff =
(v1: any, v2: any, v3: any, v4: any, v5: any, v6: any,
v7: any) => ['a', v1, v2, v3, v4, v5, v6, v7];
const e10_ff =
(v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any,
v8: any) => [v1, v2, v3, v4, v5, v6, v7, v8];
function Template(c: any, cm: boolean) {
if (cm) {
elementStart(0, MyComp);
@ -157,13 +241,14 @@ describe('array literals', () => {
f8Comp = memory(11);
elementEnd();
}
elementProperty(0, 'names', pureFunction3(e0_ff, c[5], c[6], c[7]));
elementProperty(2, 'names', pureFunction4(e2_ff, c[4], c[5], c[6], c[7]));
elementProperty(4, 'names', pureFunction5(e4_ff, c[3], c[4], c[5], c[6], c[7]));
elementProperty(6, 'names', pureFunction6(e6_ff, c[2], c[3], c[4], c[5], c[6], c[7]));
elementProperty(8, 'names', pureFunction7(e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7]));
elementProperty(0, 'names', bind(pureFunction3(e0_ff, c[5], c[6], c[7])));
elementProperty(2, 'names', bind(pureFunction4(e2_ff, c[4], c[5], c[6], c[7])));
elementProperty(4, 'names', bind(pureFunction5(e4_ff, c[3], c[4], c[5], c[6], c[7])));
elementProperty(6, 'names', bind(pureFunction6(e6_ff, c[2], c[3], c[4], c[5], c[6], c[7])));
elementProperty(
10, 'names', pureFunction8(e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]));
8, 'names', bind(pureFunction7(e8_ff, c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
elementProperty(
10, 'names', bind(pureFunction8(e10_ff, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7])));
MyComp.ngComponentDef.h(1, 0);
MyComp.ngComponentDef.h(3, 2);
MyComp.ngComponentDef.h(5, 4);
@ -178,20 +263,6 @@ describe('array literals', () => {
componentRefresh(11, 10);
}
const e0_ff = (v1: any, v2: any, v3: any) => ['a', 'b', 'c', 'd', 'e', v1, v2, v3];
const e2_ff = (v1: any, v2: any, v3: any, v4: any) => ['a', 'b', 'c', 'd', v1, v2, v3, v4];
const e4_ff =
(v1: any, v2: any, v3: any, v4: any, v5: any) => ['a', 'b', 'c', v1, v2, v3, v4, v5];
const e6_ff =
(v1: any, v2: any, v3: any, v4: any, v5: any,
v6: any) => ['a', 'b', v1, v2, v3, v4, v5, v6];
const e8_ff =
(v1: any, v2: any, v3: any, v4: any, v5: any, v6: any,
v7: any) => ['a', v1, v2, v3, v4, v5, v6, v7];
const e10_ff =
(v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any,
v8: any) => [v1, v2, v3, v4, v5, v6, v7, v8];
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']);
expect(f3Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
expect(f4Comp !.names).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']);
@ -210,6 +281,12 @@ describe('array literals', () => {
});
it('should work with pureFunctionV for 9+ bindings', () => {
const e0_ff =
(v0: any, v1: any, v2: any, v3: any, v4: any, v5: any, v6: any, v7: any,
v8: any) => ['start', v0, v1, v2, v3, v4, v5, v6, v7, v8, 'end'];
const e0_ff_1 = (v: any) => { return {name: v}; };
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']);
/**
* <my-comp [names]="['start', v0, v1, v2, v3, {name: v4}, v5, v6, v7, v8, 'end']">
* </my-comp>
@ -219,18 +296,13 @@ describe('array literals', () => {
elementStart(0, MyComp);
elementEnd();
}
elementProperty(0, 'names', pureFunctionV(e0_ff, [
elementProperty(0, 'names', bind(pureFunctionV(e0_ff, [
c[0], c[1], c[2], c[3], pureFunction1(e0_ff_1, c[4]), c[5], c[6], c[7], c[8]
]));
])));
MyComp.ngComponentDef.h(1, 0);
componentRefresh(1, 0);
}
const e0_ff =
(v: any[]) => ['start', v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], 'end'];
const e0_ff_1 = (v: any) => { return {name: v}; };
renderToHtml(Template, ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']);
expect(myComp !.names).toEqual([
'start', 'a', 'b', 'c', 'd', {name: 'e'}, 'f', 'g', 'h', 'i', 'end'
]);
@ -263,6 +335,7 @@ describe('object literals', () => {
}
it('should support an object literal', () => {
const e0_ff = (v: any) => { return {duration: 500, animation: v}; };
/** <object-comp [config]="{duration: 500, animation: name}"></object-comp> */
function Template(ctx: any, cm: boolean) {
@ -270,13 +343,11 @@ describe('object literals', () => {
elementStart(0, ObjectComp);
elementEnd();
}
elementProperty(0, 'config', pureFunction1(e0_ff, ctx.name));
elementProperty(0, 'config', bind(pureFunction1(e0_ff, ctx.name)));
ObjectComp.ngComponentDef.h(1, 0);
componentRefresh(1, 0);
}
const e0_ff = (v: any) => { return {duration: 500, animation: v}; };
renderToHtml(Template, {name: 'slide'});
const firstObj = objectComp !.config;
expect(objectComp !.config).toEqual({duration: 500, animation: 'slide'});
@ -293,6 +364,10 @@ describe('object literals', () => {
});
it('should support expressions nested deeply in object/array literals', () => {
const e0_ff = (v1: any, v2: any) => { return {animation: v1, actions: v2}; };
const e0_ff_1 = (v: any) => [{opacity: 0, duration: 0}, v];
const e0_ff_2 = (v: any) => { return {opacity: 1, duration: v}; };
/**
* <object-comp [config]="{animation: name, actions: [{ opacity: 0, duration: 0}, {opacity: 1,
* duration: duration }]}">
@ -305,16 +380,12 @@ describe('object literals', () => {
}
elementProperty(
0, 'config',
pureFunction2(
e0_ff, ctx.name, pureFunction1(e0_ff_1, pureFunction1(e0_ff_2, ctx.duration))));
bind(pureFunction2(
e0_ff, ctx.name, pureFunction1(e0_ff_1, pureFunction1(e0_ff_2, ctx.duration)))));
ObjectComp.ngComponentDef.h(1, 0);
componentRefresh(1, 0);
}
const e0_ff = (v1: any, v2: any) => { return {animation: v1, actions: v2}; };
const e0_ff_1 = (v: any) => [{opacity: 0, duration: 0}, v];
const e0_ff_2 = (v: any) => { return {opacity: 1, duration: v}; };
renderToHtml(Template, {name: 'slide', duration: 100});
expect(objectComp !.config).toEqual({
animation: 'slide',
@ -347,6 +418,12 @@ describe('object literals', () => {
animation: 'drag',
actions: [{opacity: 0, duration: 0}, {opacity: 1, duration: 500}]
});
// The property should not be set if the exp value is the same, so artificially
// setting the property to ensure it's not overwritten.
objectComp !.config = ['should not be overwritten'];
renderToHtml(Template, {name: 'drag', duration: 500});
expect(objectComp !.config).toEqual(['should not be overwritten']);
});
it('should support multiple view instances with multiple bindings', () => {
@ -371,7 +448,8 @@ describe('object literals', () => {
elementEnd();
}
elementProperty(
0, 'config', pureFunction2(e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration));
0, 'config',
bind(pureFunction2(e0_ff, ctx.configs[i].opacity, ctx.configs[i].duration)));
ObjectComp.ngComponentDef.h(1, 0);
componentRefresh(1, 0);
embeddedViewEnd();