refactor(ivy): move hostVars/hostAttrs from instruction to DirectiveDef (#34683)

This change moves information from instructions to declarative position:
- `ɵɵallocHostVars(vars)` => `DirectiveDef.hostVars`
- `ɵɵelementHostAttrs(attrs)` => `DirectiveDef.hostAttrs`

When merging directives it is necessary to know about `hostVars` and `hostAttrs`. Before this change the information was stored in the `hostBindings` function. This was problematic, because in order to get to the information the `hostBindings` would have to be executed. In order for `hostBindings` to be executed the directives would have to be instantiated. This means that the directive instantiation would happen before we had knowledge about the `hostAttrs` and as a result the directive could observe in the constructor that not all of the `hostAttrs` have been applied. This further complicates the runtime as we have to apply `hostAttrs` in parts over many invocations.

`ɵɵallocHostVars` was unnecessarily complicated because it would have to update the `LView` (and Blueprint) while existing directives are already executing. By moving it out of `hostBindings` function we can access it statically and we can create correct `LView` (and Blueprint) in a single pass.

This change only changes how the instructions are generated, but does not change the runtime much. (We cheat by emulating the old behavior by calling `ɵɵallocHostVars` and `ɵɵelementHostAttrs`) Subsequent change will refactor the runtime to take advantage of the static information.

PR Close #34683
This commit is contained in:
Miško Hevery
2020-01-08 11:32:33 -08:00
parent 239c602f69
commit d566621fef
33 changed files with 751 additions and 185 deletions

View File

@ -668,13 +668,11 @@ describe('compiler compliance: bindings', () => {
};
const HostBindingDirDeclaration = `
HostBindingDir.ɵdir = $r3$.ɵɵdefineDirective({
type: HostBindingDir,
selectors: [["", "hostBindingDir", ""]],
HostBindingDir.ɵdir = $r3$.ɵɵdefineDirective({
type: HostBindingDir,
selectors: [["", "hostBindingDir", ""]],
hostVars: 1,
hostBindings: function HostBindingDir_HostBindings(rf, ctx, elIndex) {
if (rf & 1) {
$r3$.ɵɵallocHostVars(1);
}
if (rf & 2) {
$r3$.ɵɵhostProperty("id", ctx.dirId);
}
@ -717,10 +715,8 @@ describe('compiler compliance: bindings', () => {
HostBindingComp.ɵcmp = $r3$.ɵɵdefineComponent({
type: HostBindingComp,
selectors: [["host-binding-comp"]],
hostVars: 3,
hostBindings: function HostBindingComp_HostBindings(rf, ctx, elIndex) {
if (rf & 1) {
$r3$.ɵɵallocHostVars(3);
}
if (rf & 2) {
$r3$.ɵɵhostProperty("id", $r3$.ɵɵpureFunction1(1, $ff$, ctx.id));
}
@ -764,10 +760,8 @@ describe('compiler compliance: bindings', () => {
HostAttributeDir.ɵdir = $r3$.ɵɵdefineDirective({
type: HostAttributeDir,
selectors: [["", "hostAttributeDir", ""]],
hostVars: 1,
hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) {
if (rf & 1) {
$r3$.ɵɵallocHostVars(1);
}
if (rf & 2) {
$r3$.ɵɵattribute("required", ctx.required);
}
@ -803,16 +797,10 @@ describe('compiler compliance: bindings', () => {
};
const HostAttributeDirDeclaration = `
const $c0$ = ["aria-label", "label"];
HostAttributeDir.ɵdir = $r3$.ɵɵdefineDirective({
type: HostAttributeDir,
selectors: [["", "hostAttributeDir", ""]],
hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) {
if (rf & 1) {
$r3$.ɵɵelementHostAttrs($c0$);
}
}
hostAttrs: ["aria-label", "label"]
});
`;
@ -859,32 +847,20 @@ describe('compiler compliance: bindings', () => {
};
const CompAndDirDeclaration = `
const $c0$ = ["title", "hello there from component", ${AttributeMarker.Styles}, "opacity", "1"];
const $c1$ = ["title", "hello there from directive", ${AttributeMarker.Classes}, "one", "two", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"];
HostAttributeComp.ɵcmp = $r3$.ɵɵdefineComponent({
type: HostAttributeComp,
selectors: [["my-host-attribute-component"]],
hostBindings: function HostAttributeComp_HostBindings(rf, ctx, elIndex) {
if (rf & 1) {
$r3$.ɵɵelementHostAttrs($c0$);
}
}
hostAttrs: ["title", "hello there from component", ${AttributeMarker.Styles}, "opacity", "1"],
HostAttributeDir.ɵdir = $r3$.ɵɵdefineDirective({
type: HostAttributeDir,
selectors: [["", "hostAttributeDir", ""]],
hostAttrs: ["title", "hello there from directive", ${AttributeMarker.Classes}, "one", "two", ${AttributeMarker.Styles}, "width", "200px", "height", "500px"],
hostVars: 2,
hostBindings: function HostAttributeDir_HostBindings(rf, ctx, elIndex) {
if (rf & 1) {
$r3$.ɵɵallocHostVars(2);
$r3$.ɵɵelementHostAttrs($c1$);
}
}
`;
`;
const result = compile(files, angularFiles);
const source = result.source;