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,
selectors: [["view-query-component"]],
factory: function ViewQueryComponent_Factory() { return new ViewQueryComponent(); },
template: function ViewQueryComponent_Template(rf, ctx) {
var $tmp$;
viewQuery: function ViewQueryComponent_Query(rf, ctx) {
if (rf & 1) {
$r3$.ɵQ(0, SomeDirective, true);
$r3$.ɵEe(1, "div", $e0_attrs$);
}
if (rf & 2) {
var $tmp$;
($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]
});`;

View File

@ -27,8 +27,8 @@ import {Render3ParseResult} from '../r3_template_transform';
import {typeWithParameters} from '../util';
import {R3ComponentDef, R3ComponentMetadata, R3DirectiveDef, R3DirectiveMetadata, R3QueryMetadata} from './api';
import {BindingScope, TemplateDefinitionBuilder} from './template';
import {CONTEXT_NAME, DefinitionMap, ID_SEPARATOR, MEANING_SEPARATOR, TEMPORARY_NAME, asLiteral, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator, unsupported} from './util';
import {BindingScope, TemplateDefinitionBuilder, renderFlagCheckIfStmt} from './template';
import {CONTEXT_NAME, DefinitionMap, ID_SEPARATOR, MEANING_SEPARATOR, RENDER_FLAGS, TEMPORARY_NAME, asLiteral, conditionallyCreateMapObjectLiteral, getQueryPredicate, temporaryAllocator, unsupported} from './util';
function baseDirectiveFields(
meta: R3DirectiveMetadata, constantPool: ConstantPool,
@ -138,6 +138,10 @@ export function compileComponentFromMetadata(
directiveMatcher = matcher;
}
if (meta.viewQueries.length) {
definitionMap.set('viewQuery', createViewQueriesFunction(meta, constantPool));
}
// e.g. `template: function MyComponent_Template(_ctx, _cm) {...}`
const templateTypeName = meta.name;
const templateName = templateTypeName ? `${templateTypeName}_Template` : null;
@ -322,32 +326,22 @@ function selectorsFromGlobalMetadata(
return o.NULL_EXPR;
}
/**
*
* @param meta
* @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);
function createQueryDefinition(
query: R3QueryMetadata, constantPool: ConstantPool, idx: number | null): o.Expression {
const predicate = getQueryPredicate(query, constantPool);
// e.g. r3.Q(null, somePredicate, false) or r3.Q(null, ['div'], false)
const parameters = [
o.literal(null, o.INFERRED_TYPE),
predicate,
o.literal(query.descendants),
];
// e.g. r3.Q(null, somePredicate, false) or r3.Q(0, ['div'], false)
const parameters = [
o.literal(idx, o.INFERRED_TYPE),
predicate,
o.literal(query.descendants),
];
if (query.read) {
parameters.push(query.read);
}
queryDefinitions.push(o.importExpr(R3.query).callFn(parameters));
if (query.read) {
parameters.push(query.read);
}
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
@ -371,11 +365,10 @@ function createHostAttributesArray(meta: R3DirectiveMetadata): o.Expression|null
// Return a contentQueries function or null if one is not necessary.
function createContentQueriesFunction(
meta: R3DirectiveMetadata, constantPool: ConstantPool): o.Expression|null {
const queryDefinitions = createQueryDefinitions(meta.queries, constantPool);
if (queryDefinitions) {
const statements: o.Statement[] = queryDefinitions.map((qd: o.Expression) => {
return o.importExpr(R3.registerContentQuery).callFn([qd]).toStmt();
if (meta.queries.length) {
const statements: o.Statement[] = meta.queries.map((query: R3QueryMetadata) => {
const queryDefinition = createQueryDefinition(query, constantPool, null);
return o.importExpr(R3.registerContentQuery).callFn([queryDefinition]).toStmt();
});
const typeName = meta.name;
return o.fn(
@ -426,6 +419,40 @@ function createContentQueriesRefreshFunction(meta: R3DirectiveMetadata): o.Expre
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.
function createHostBindingsFunction(
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 {
private _dataIndex = 0;
private _bindingContext = 0;
@ -54,7 +60,6 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
private _variableCode: o.Statement[] = [];
private _bindingCode: o.Statement[] = [];
private _postfixCode: o.Statement[] = [];
private _temporary = temporaryAllocator(this._prefixCode, TEMPORARY_NAME);
private _valueConverter: ValueConverter;
private _unsupported = unsupported;
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 pipeTypeByName: Map<string, o.Expression>, private pipes: Set<o.Expression>,
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 =
parentBindingScope.nestedScope((lhsVar: o.ReadVarExpr, expression: o.Expression) => {
this._bindingCode.push(
@ -127,32 +135,6 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
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);
if (this._pureFunctionSlots > 0) {
@ -161,15 +143,11 @@ export class TemplateDefinitionBuilder implements t.Visitor<void>, LocalResolver
}
const creationCode = this._creationCode.length > 0 ?
[o.ifStmt(
o.variable(RENDER_FLAGS).bitwiseAnd(o.literal(core.RenderFlags.Create), null, false),
this._creationCode)] :
[renderFlagCheckIfStmt(core.RenderFlags.Create, this._creationCode)] :
[];
const updateCode = this._bindingCode.length > 0 ?
[o.ifStmt(
o.variable(RENDER_FLAGS).bitwiseAnd(o.literal(core.RenderFlags.Update), null, false),
this._bindingCode)] :
[renderFlagCheckIfStmt(core.RenderFlags.Update, this._bindingCode)] :
[];
// Generate maps of placeholder name to node indexes