refactor(core): Remove reliance on TNodeType.View. (#38707)

`TNodeType.View` was created to support inline views. That feature did
not materialize and we have since removed the instructions for it, leave
 an unneeded `TNodeType.View` which was still used in a very
 inconsistent way. This change no longer created `TNodeType.View` (and
 there will be a follow up chang to completely remove it.)

Also simplified the mental model so that `LView[HOST]`/`LView[T_HOST]`
always point to the insertion location of the `LView`.

PR Close #38707
This commit is contained in:
Misko Hevery
2020-09-14 11:21:15 -07:00
parent b613639e8a
commit 4645f43c3c
45 changed files with 346 additions and 351 deletions

View File

@ -7,7 +7,7 @@
*/
import {CommonModule} from '@angular/common';
import {Attribute, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, forwardRef, Host, HostBinding, Inject, Injectable, InjectionToken, INJECTOR, Injector, Input, LOCALE_ID, ModuleWithProviders, NgModule, NgZone, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, ViewRef, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core';
import {Attribute, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, Directive, ElementRef, EventEmitter, forwardRef, Host, HostBinding, Inject, Injectable, InjectionToken, INJECTOR, Injector, Input, LOCALE_ID, NgModule, NgZone, Optional, Output, Pipe, PipeTransform, Self, SkipSelf, TemplateRef, ViewChild, ViewContainerRef, ViewRef, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID} from '@angular/core';
import {ɵINJECTOR_SCOPE} from '@angular/core/src/core';
import {ViewRef as ViewRefInternal} from '@angular/core/src/render3/view_ref';
import {TestBed} from '@angular/core/testing';

View File

@ -53,7 +53,7 @@ describe('acceptance integration tests', () => {
expect(fixture.nativeElement.innerHTML).toEqual('<h1>Hello, World!</h1>');
onlyInIvy('perf counters').expectPerfCounters({
tView: 2, // Host view + App
tNode: 4, // Host Node + App Node + <span> + #text
tNode: 3, // Host Node + <h1> + #text
});
fixture.componentInstance.name = 'New World';
@ -63,7 +63,7 @@ describe('acceptance integration tests', () => {
// Assert that the tView/tNode count does not increase (they are correctly cached)
onlyInIvy('perf counters').expectPerfCounters({
tView: 2,
tNode: 4,
tNode: 3,
});
});
});

View File

@ -797,7 +797,7 @@ describe('styling', () => {
onlyInIvy('perf counters').expectPerfCounters({
rendererSetStyle: 1,
tNode: 3,
tNode: 2,
});
});

View File

@ -704,9 +704,6 @@
{
"name": "addHostBindingsToExpandoInstructions"
},
{
"name": "addRemoveViewFromContainer"
},
{
"name": "addToArray"
},
@ -821,9 +818,6 @@
{
"name": "createPlatformFactory"
},
{
"name": "createTNode"
},
{
"name": "createTView"
},
@ -974,9 +968,6 @@
{
"name": "getConstant"
},
{
"name": "getContainerRenderParent"
},
{
"name": "getDOM"
},
@ -1064,9 +1055,6 @@
{
"name": "getParentInjectorView"
},
{
"name": "getParentInjectorViewOffset"
},
{
"name": "getParentState"
},

View File

@ -59,9 +59,6 @@
{
"name": "allocLFrame"
},
{
"name": "appendChild"
},
{
"name": "attachPatchData"
},
@ -110,6 +107,9 @@
{
"name": "extractPipeDef"
},
{
"name": "getBeforeNodeForView"
},
{
"name": "getCheckNoChangesMode"
},
@ -235,5 +235,8 @@
},
{
"name": "viewAttachedToChangeDetector"
},
{
"name": "ɵɵtext"
}
]

View File

@ -926,9 +926,6 @@
{
"name": "addHostBindingsToExpandoInstructions"
},
{
"name": "addRemoveViewFromContainer"
},
{
"name": "addToArray"
},
@ -1070,9 +1067,6 @@
{
"name": "createRouterScroller"
},
{
"name": "createTNode"
},
{
"name": "createTView"
},
@ -1286,9 +1280,6 @@
{
"name": "getConstant"
},
{
"name": "getContainerRenderParent"
},
{
"name": "getCurrentQueryIndex"
},
@ -1394,9 +1385,6 @@
{
"name": "getParentInjectorView"
},
{
"name": "getParentInjectorViewOffset"
},
{
"name": "getParentState"
},

View File

@ -179,9 +179,6 @@
{
"name": "addHostBindingsToExpandoInstructions"
},
{
"name": "addRemoveViewFromContainer"
},
{
"name": "addToArray"
},
@ -260,9 +257,6 @@
{
"name": "createLView"
},
{
"name": "createTNode"
},
{
"name": "createTView"
},
@ -353,9 +347,6 @@
{
"name": "getConstant"
},
{
"name": "getContainerRenderParent"
},
{
"name": "getDebugContext"
},
@ -425,9 +416,6 @@
{
"name": "getParentInjectorView"
},
{
"name": "getParentInjectorViewOffset"
},
{
"name": "getParentState"
},

View File

@ -226,8 +226,8 @@ describe('di', () => {
describe('getOrCreateNodeInjector', () => {
it('should handle initial undefined state', () => {
const contentView = createLView(
null, createTView(TViewType.Component, -1, null, 1, 0, null, null, null, null, null), {},
LViewFlags.CheckAlways, null, null, {} as any, {} as any);
null, createTView(TViewType.Component, null, null, 1, 0, null, null, null, null, null),
{}, LViewFlags.CheckAlways, null, null, {} as any, {} as any, null, null);
enterView(contentView);
try {
const parentTNode = getOrCreateTNode(contentView[TVIEW], 0, TNodeType.Element, null, null);

View File

@ -26,7 +26,7 @@ describe('lView_debug', () => {
let tNode!: TNodeDebug;
let tView!: TView;
beforeEach(() => {
tView = createTView(TViewType.Component, 0, null, 0, 0, null, null, null, null, null);
tView = createTView(TViewType.Component, null, null, 0, 0, null, null, null, null, null);
tNode = createTNode(tView, null!, TNodeType.Element, 0, '', null) as TNodeDebug;
});
afterEach(() => tNode = tView = null!);

View File

@ -36,7 +36,7 @@ export function enterViewWithOneDiv() {
const vars = 60; // Space for directive expando, template, component + 3 directives if we assume
// that each consume 10 slots.
const tView = createTView(
TViewType.Component, -1, emptyTemplate, consts, vars, null, null, null, null, null);
TViewType.Component, null, emptyTemplate, consts, vars, null, null, null, null, null);
// Just assume that the expando starts after 10 initial bindings.
tView.expandoStartIndex = HEADER_OFFSET + 10;
const tNode = tView.firstChild = createTNode(tView, null!, TNodeType.Element, 0, 'div', null);

View File

@ -91,7 +91,6 @@ export function isTView(obj: any): obj is TView {
}
const ShapeOfTView: ShapeOf<TView> = {
type: true,
id: true,
blueprint: true,
template: true,
viewQuery: true,

View File

@ -52,7 +52,7 @@ describe('render3 matchers', () => {
});
describe('matchTView', () => {
const tView = createTView(TViewType.Root, 1, null, 2, 3, null, null, null, null, null);
const tView = createTView(TViewType.Root, null, null, 2, 3, null, null, null, null, null);
it('should match', () => {
expect(tView).toEqual(matchTView());
expect(tView).toEqual(matchTView({type: TViewType.Root}));
@ -60,7 +60,7 @@ describe('render3 matchers', () => {
});
});
describe('matchTNode', () => {
const tView = createTView(TViewType.Root, 1, null, 2, 3, null, null, null, null, null);
const tView = createTView(TViewType.Root, null, null, 2, 3, null, null, null, null, null);
const tNode = createTNode(tView, null, TNodeType.Element, 1, 'tagName', []);
it('should match', () => {

View File

@ -75,12 +75,12 @@ function testTemplate(rf: RenderFlags, ctx: any) {
}
const rootLView = createLView(
null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null);
null, createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null, null, null, null, null);
const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode;
const embeddedTView = createTView(
TViewType.Embedded, -1, testTemplate, 21, 10, [Tooltip.ɵdir], null, null, null,
TViewType.Embedded, null, testTemplate, 21, 10, [Tooltip.ɵdir], null, null, null,
[['position', 'top', 3, 'tooltip']]);
// create view once so we don't profile the first create pass

View File

@ -64,12 +64,12 @@ function testTemplate(rf: RenderFlags, ctx: any) {
}
const rootLView = createLView(
null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null);
null, createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null, null, null, null, null);
const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode;
const embeddedTView = createTView(
TViewType.Embedded, -1, testTemplate, 21, 0, null, null, null, null, [[
TViewType.Embedded, null, testTemplate, 21, 0, null, null, null, null, [[
'name1', 'value1', 'name2', 'value2', 'name3', 'value3', 'name4', 'value4', 'name5', 'value5'
]]);

View File

@ -66,12 +66,12 @@ function testTemplate(rf: RenderFlags, ctx: any) {
}
const rootLView = createLView(
null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null);
null, createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null, null, null, null, null);
const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode;
const embeddedTView = createTView(
TViewType.Embedded, -1, testTemplate, 11, 0, null, null, null, null, [[3, 'click', 'input']]);
TViewType.Embedded, null, testTemplate, 11, 0, null, null, null, null, [[3, 'click', 'input']]);
// create view once so we don't profile the first create pass
createAndRenderLView(rootLView, embeddedTView, viewTNode);

View File

@ -59,12 +59,12 @@ function testTemplate(rf: RenderFlags, ctx: any) {
}
const rootLView = createLView(
null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null);
null, createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null, null, null, null, null);
const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode;
const embeddedTView = createTView(
TViewType.Root, -1, testTemplate, 2, 0, [NgIfLike.ɵdir], null, null, null,
TViewType.Root, null, testTemplate, 2, 0, [NgIfLike.ɵdir], null, null, null,
[['viewManipulation', '']]);
// create view once so we don't profile first template pass

View File

@ -22,7 +22,8 @@ const renderer = rendererFactory.createRenderer(null, null);
export function createAndRenderLView(
parentLView: LView, tView: TView, hostTNode: TViewNode): LView {
const embeddedLView = createLView(
parentLView, tView, {}, LViewFlags.CheckAlways, null, hostTNode, rendererFactory, renderer);
parentLView, tView, {}, LViewFlags.CheckAlways, null, hostTNode, rendererFactory, renderer,
null, null);
renderView(tView, embeddedLView, null);
return embeddedLView;
}
@ -49,12 +50,12 @@ export function setupTestHarness(
embeddedViewContext: any = {}, consts: TAttributes[]|null = null,
directiveRegistry: DirectiveDefList|null = null): TestHarness {
// Create a root view with a container
const hostTView = createTView(TViewType.Root, -1, null, 1, 0, null, null, null, null, consts);
const hostTView = createTView(TViewType.Root, null, null, 1, 0, null, null, null, null, consts);
const tContainerNode = getOrCreateTNode(hostTView, 0, TNodeType.Container, null, null);
const hostNode = renderer.createElement('div');
const hostLView = createLView(
null, hostTView, {}, LViewFlags.CheckAlways | LViewFlags.IsRoot, hostNode, null,
rendererFactory, renderer);
rendererFactory, renderer, null, null);
const mockRCommentNode = renderer.createComment('');
const lContainer =
createLContainer(mockRCommentNode, hostLView, mockRCommentNode, tContainerNode);
@ -63,13 +64,14 @@ export function setupTestHarness(
// create test embedded views
const embeddedTView = createTView(
TViewType.Embedded, -1, templateFn, decls, vars, directiveRegistry, null, null, null, consts);
TViewType.Embedded, null, templateFn, decls, vars, directiveRegistry, null, null, null,
consts);
const viewTNode = createTNode(hostTView, null, TNodeType.View, -1, null, null) as TViewNode;
function createEmbeddedLView(): LView {
const embeddedLView = createLView(
hostLView, embeddedTView, embeddedViewContext, LViewFlags.CheckAlways, null, viewTNode,
rendererFactory, renderer);
rendererFactory, renderer, null, null);
renderView(embeddedTView, embeddedLView, embeddedViewContext);
return embeddedLView;
}

View File

@ -52,12 +52,12 @@ function testTemplate(rf: RenderFlags, ctx: any) {
}
const rootLView = createLView(
null, createTView(TViewType.Root, -1, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null);
null, createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null), {},
LViewFlags.IsRoot, null, null, null, null, null, null);
const viewTNode = createTNode(null!, null, TNodeType.View, -1, null, null) as TViewNode;
const embeddedTView = createTView(
TViewType.Embedded, -1, testTemplate, 21, 10, [ToDestroy.ɵdir], null, null, null,
TViewType.Embedded, null, testTemplate, 21, 10, [ToDestroy.ɵdir], null, null, null,
[['to-destroy']]);
// create view once so we don't profile the first create pass

View File

@ -261,10 +261,10 @@ export function renderTemplate<T>(
const renderer = providedRendererFactory.createRenderer(null, null);
// We need to create a root view so it's possible to look up the host element through its index
const tView = createTView(TViewType.Root, -1, null, 1, 0, null, null, null, null, null);
const tView = createTView(TViewType.Root, null, null, 1, 0, null, null, null, null, null);
const hostLView = createLView(
null, tView, {}, LViewFlags.CheckAlways | LViewFlags.IsRoot, null, null,
providedRendererFactory, renderer);
providedRendererFactory, renderer, null, null);
enterView(hostLView);
const def: ComponentDef<any> = ɵɵdefineComponent({
@ -282,7 +282,7 @@ export function renderTemplate<T>(
hostLView[hostTNode.index] = hostNode;
componentView = createLView(
hostLView, componentTView, context, LViewFlags.CheckAlways, hostNode, hostTNode,
providedRendererFactory, renderer, sanitizer);
providedRendererFactory, renderer, sanitizer || null, null);
}
renderComponentOrTemplate(componentView[TVIEW], componentView, templateFn, context);
return componentView;

View File

@ -13,7 +13,7 @@ import {TViewType} from '@angular/core/src/render3/interfaces/view';
describe('view_utils', () => {
it('should verify unwrap methods', () => {
const div = document.createElement('div');
const tView = createTView(TViewType.Root, 0, null, 0, 0, null, null, null, null, null);
const tView = createTView(TViewType.Root, null, null, 0, 0, null, null, null, null, null);
const lView = createLView(null, tView, {}, 0, div, null, {} as any, {} as any, null, null);
const tNode = createTNode(null!, null, 3, 0, 'div', []);
const lContainer = createLContainer(lView, lView, div, tNode);