fix(ivy): update compiler with latest runtime for view queries (#25061)

PR Close #25061
This commit is contained in:
Pawel Kozlowski
2018-07-24 11:56:35 +02:00
committed by Victor Berchet
parent 0bcf20c9fa
commit 1e28495c89
3 changed files with 75 additions and 66 deletions

View File

@ -963,16 +963,20 @@ describe('compiler compliance', () => {
type: ViewQueryComponent, type: ViewQueryComponent,
selectors: [["view-query-component"]], selectors: [["view-query-component"]],
factory: function ViewQueryComponent_Factory() { return new ViewQueryComponent(); }, factory: function ViewQueryComponent_Factory() { return new ViewQueryComponent(); },
template: function ViewQueryComponent_Template(rf, ctx) { viewQuery: function ViewQueryComponent_Query(rf, ctx) {
var $tmp$;
if (rf & 1) { if (rf & 1) {
$r3$.ɵQ(0, SomeDirective, true); $r3$.ɵQ(0, SomeDirective, true);
$r3$.ɵEe(1, "div", $e0_attrs$);
} }
if (rf & 2) { if (rf & 2) {
var $tmp$;
($r3$.ɵqR(($tmp$ = $r3$.ɵld(0))) && (ctx.someDir = $tmp$.first)); ($r3$.ɵqR(($tmp$ = $r3$.ɵld(0))) && (ctx.someDir = $tmp$.first));
} }
}, },
template: function ViewQueryComponent_Template(rf, ctx) {
if (rf & 1) {
$r3$.ɵEe(1, "div", $e0_attrs$);
}
},
directives:[SomeDirective] directives:[SomeDirective]
});`; });`;

View File

@ -27,8 +27,8 @@ import {Render3ParseResult} from '../r3_template_transform';
import {typeWithParameters} from '../util'; import {typeWithParameters} from '../util';
import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3QueryMetadata} from './api'; import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3QueryMetadata} from './api';
import {BindingScope, TemplateDefinitionBuilder} from './template'; import {BindingScope, TemplateDefinitionBuilder, renderFlagCheckIfStmt} from './template';
import {CONTEXT_NAME, DefinitionMap, ID_SEPARATOR, MEANING_SEPARATOR, TEMPORARY_NAME, asLiteral, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator, unsupported} from './util'; import {CONTEXT_NAME, DefinitionMap, ID_SEPARATOR, MEANING_SEPARATOR, RENDER_FLAGS, TEMPORARY_NAME, asLiteral, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator, unsupported} from './util';
function baseDirectiveFields( function baseDirectiveFields(
meta: R3DirectiveMetadata, constantPool: ConstantPool, meta: R3DirectiveMetadata, constantPool: ConstantPool,
@ -138,6 +138,10 @@ export function compileComponentFromMetadata(
directiveMatcher = matcher; directiveMatcher = matcher;
} }
if (meta.viewQueries.length) {
definitionMap.set('viewQuery', createViewQueriesFunction(meta, constantPool));
}
// e.g. `template: function MyComponent_Template(_ctx, _cm) {...}` // e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
const templateTypeName = meta.name; const templateTypeName = meta.name;
const templateName = templateTypeName ? `${templateTypeName}_Template` : null; const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
@ -322,32 +326,22 @@ function selectorsFromGlobalMetadata(
return o.NULL_EXPR; return o.NULL_EXPR;
} }
/** function createQueryDefinition(
* query: R3QueryMetadata, constantPool: ConstantPool, idx: number | null): o.Expression {
* @param meta const predicate = getQueryPredicate(query, constantPool);
* @param constantPool
*/
function createQueryDefinitions(
queries: R3QueryMetadata[], constantPool: ConstantPool): o.Expression[]|undefined {
const queryDefinitions: o.Expression[] = [];
for (let i = 0; i < queries.length; i++) {
const query = queries[i];
const predicate = getQueryPredicate(query, constantPool);
// e.g. r3.Q(null, somePredicate, false) or r3.Q(null, ['div'], false) // e.g. r3.Q(null, somePredicate, false) or r3.Q(0, ['div'], false)
const parameters = [ const parameters = [
o.literal(null, o.INFERRED_TYPE), o.literal(idx, o.INFERRED_TYPE),
predicate, predicate,
o.literal(query.descendants), o.literal(query.descendants),
]; ];
if (query.read) { if (query.read) {
parameters.push(query.read); parameters.push(query.read);
}
queryDefinitions.push(o.importExpr(R3.query).callFn(parameters));
} }
return queryDefinitions.length > 0 ? queryDefinitions : undefined;
return o.importExpr(R3.query).callFn(parameters);
} }
// Turn a directive selector into an R3-compatible selector for directive def // Turn a directive selector into an R3-compatible selector for directive def
@ -371,11 +365,10 @@ function createHostAttributesArray(meta: R3DirectiveMetadata): o.Expression|null
// Return a contentQueries function or null if one is not necessary. // Return a contentQueries function or null if one is not necessary.
function createContentQueriesFunction( function createContentQueriesFunction(
meta: R3DirectiveMetadata, constantPool: ConstantPool): o.Expression|null { meta: R3DirectiveMetadata, constantPool: ConstantPool): o.Expression|null {
const queryDefinitions = createQueryDefinitions(meta.queries, constantPool); if (meta.queries.length) {
const statements: o.Statement[] = meta.queries.map((query: R3QueryMetadata) => {
if (queryDefinitions) { const queryDefinition = createQueryDefinition(query, constantPool, null);
const statements: o.Statement[] = queryDefinitions.map((qd: o.Expression) => { return o.importExpr(R3.registerContentQuery).callFn([queryDefinition]).toStmt();
return o.importExpr(R3.registerContentQuery).callFn([qd]).toStmt();
}); });
const typeName = meta.name; const typeName = meta.name;
return o.fn( return o.fn(
@ -426,6 +419,40 @@ function createContentQueriesRefreshFunction(meta: R3DirectiveMetadata): o.Expre
return null; return null;
} }
// Define and update any view queries
function createViewQueriesFunction(
meta: R3ComponentMetadata, constantPool: ConstantPool): o.Expression {
const createStatements: o.Statement[] = [];
const updateStatements: o.Statement[] = [];
const tempAllocator = temporaryAllocator(updateStatements, TEMPORARY_NAME);
for (let i = 0; i < meta.viewQueries.length; i++) {
const query = meta.viewQueries[i];
// creation, e.g. r3.Q(0, somePredicate, true);
const queryDefinition = createQueryDefinition(query, constantPool, i);
createStatements.push(queryDefinition.toStmt());
// update, e.g. (r3.qR(tmp = r3.ɵld(0)) && (ctx.someDir = tmp));
const temporary = tempAllocator();
const getQueryList = o.importExpr(R3.load).callFn([o.literal(i)]);
const refresh = o.importExpr(R3.queryRefresh).callFn([temporary.set(getQueryList)]);
const updateDirective = o.variable(CONTEXT_NAME)
.prop(query.propertyName)
.set(query.first ? temporary.prop('first') : temporary);
updateStatements.push(refresh.and(updateDirective).toStmt());
}
const viewQueryFnName = meta.name ? `${meta.name}_Query` : null;
return o.fn(
[new o.FnParam(RENDER_FLAGS, o.NUMBER_TYPE), new o.FnParam(CONTEXT_NAME, null)],
[
renderFlagCheckIfStmt(core.RenderFlags.Create, createStatements),
renderFlagCheckIfStmt(core.RenderFlags.Update, updateStatements)
],
o.INFERRED_TYPE, null, viewQueryFnName);
}
// Return a host binding function or null if one is not necessary. // Return a host binding function or null if one is not necessary.
function createHostBindingsFunction( function createHostBindingsFunction(
meta: R3DirectiveMetadata, bindingParser: BindingParser): o.Expression|null { meta: R3DirectiveMetadata, bindingParser: BindingParser): o.Expression|null {

View File

@ -46,6 +46,12 @@ function mapBindingToInstruction(type: BindingType): o.ExternalReference|undefin
} }
} }
// if (rf & flags) { .. }
export function renderFlagCheckIfStmt(
flags: core.RenderFlags, statements: o.Statement[]): o.IfStmt {
return o.ifStmt(o.variable(RENDER_FLAGS).bitwiseAnd(o.literal(flags), null, false), statements);
}
export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver { export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver {
private _dataIndex = 0; private _dataIndex = 0;
private _bindingContext = 0; private _bindingContext = 0;
@ -54,7 +60,6 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
private _variableCode: o.Statement[] = []; private _variableCode: o.Statement[] = [];
private _bindingCode: o.Statement[] = []; private _bindingCode: o.Statement[] = [];
private _postfixCode: o.Statement[] = []; private _postfixCode: o.Statement[] = [];
private _temporary = temporaryAllocator(this._prefixCode, TEMPORARY_NAME);
private _valueConverter: ValueConverter; private _valueConverter: ValueConverter;
private _unsupported = unsupported; private _unsupported = unsupported;
private _bindingScope: BindingScope; private _bindingScope: BindingScope;
@ -75,6 +80,9 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
private directiveMatcher: SelectorMatcher|null, private directives: Set<o.Expression>, private directiveMatcher: SelectorMatcher|null, private directives: Set<o.Expression>,
private pipeTypeByName: Map<string, o.Expression>, private pipes: Set<o.Expression>, private pipeTypeByName: Map<string, o.Expression>, private pipes: Set<o.Expression>,
private _namespace: o.ExternalReference) { private _namespace: o.ExternalReference) {
// view queries can take up space in data and allocation happens earlier (in the "viewQuery"
// function)
this._dataIndex = viewQueries.length;
this._bindingScope = this._bindingScope =
parentBindingScope.nestedScope((lhsVar: o.ReadVarExpr, expression: o.Expression) => { parentBindingScope.nestedScope((lhsVar: o.ReadVarExpr, expression: o.Expression) => {
this._bindingCode.push( this._bindingCode.push(
@ -127,32 +135,6 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
this.instruction(this._creationCode, null, R3.projectionDef, ...parameters); this.instruction(this._creationCode, null, R3.projectionDef, ...parameters);
} }
// Define and update any view queries
for (let query of this.viewQueries) {
// e.g. r3.Q(0, somePredicate, true);
const querySlot = this.allocateDataSlot();
const predicate = getQueryPredicate(query, this.constantPool);
const args: o.Expression[] = [
o.literal(querySlot, o.INFERRED_TYPE),
predicate,
o.literal(query.descendants, o.INFERRED_TYPE),
];
if (query.read) {
args.push(query.read);
}
this.instruction(this._creationCode, null, R3.query, ...args);
// (r3.qR(tmp = r3.ɵld(0)) && (ctx.someDir = tmp));
const temporary = this._temporary();
const getQueryList = o.importExpr(R3.load).callFn([o.literal(querySlot)]);
const refresh = o.importExpr(R3.queryRefresh).callFn([temporary.set(getQueryList)]);
const updateDirective = o.variable(CONTEXT_NAME)
.prop(query.propertyName)
.set(query.first ? temporary.prop('first') : temporary);
this._bindingCode.push(refresh.and(updateDirective).toStmt());
}
t.visitAll(this, nodes); t.visitAll(this, nodes);
if (this._pureFunctionSlots > 0) { if (this._pureFunctionSlots > 0) {
@ -161,15 +143,11 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
} }
const creationCode = this._creationCode.length > 0 ? const creationCode = this._creationCode.length > 0 ?
[o.ifStmt( [renderFlagCheckIfStmt(core.RenderFlags.Create, this._creationCode)] :
o.variable(RENDER_FLAGS).bitwiseAnd(o.literal(core.RenderFlags.Create), null, false),
this._creationCode)] :
[]; [];
const updateCode = this._bindingCode.length > 0 ? const updateCode = this._bindingCode.length > 0 ?
[o.ifStmt( [renderFlagCheckIfStmt(core.RenderFlags.Update, this._bindingCode)] :
o.variable(RENDER_FLAGS).bitwiseAnd(o.literal(core.RenderFlags.Update), null, false),
this._bindingCode)] :
[]; [];
// Generate maps of placeholder name to node indexes // Generate maps of placeholder name to node indexes