Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert commits from PR that are causing internal test failures #38765

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
88 changes: 50 additions & 38 deletions packages/compiler-cli/src/ngtsc/annotations/src/component.ts
Expand Up @@ -16,6 +16,7 @@ import {DefaultImportRecorder, ModuleResolver, Reference, ReferenceEmitter} from
import {DependencyTracker} from '../../incremental/api';
import {IndexingContext} from '../../indexer';
import {ClassPropertyMapping, DirectiveMeta, DirectiveTypeCheckMeta, extractDirectiveTypeCheckMeta, InjectableClassRegistry, MetadataReader, MetadataRegistry} from '../../metadata';
import {flattenInheritedDirectiveMetadata} from '../../metadata/src/inheritance';
import {EnumValue, PartialEvaluator} from '../../partial_evaluator';
import {ClassDeclaration, Decorator, ReflectionHost, reflectObjectLiteral} from '../../reflection';
import {ComponentScopeReader, LocalModuleScopeRegistry} from '../../scope';
Expand All @@ -30,7 +31,6 @@ import {createValueHasWrongTypeError, getDirectiveDiagnostics, getProviderDiagno
import {extractDirectiveMetadata, parseFieldArrayValue} from './directive';
import {compileNgFactoryDefField} from './factory';
import {generateSetClassMetadataCall} from './metadata';
import {TypeCheckScopes} from './typecheck_scopes';
import {findAngularDecorator, isAngularCoreReference, isExpressionForwardReference, readBaseClass, resolveProvidersRequiringFactory, unwrapExpression, wrapFunctionExpressionsInParens} from './util';

const EMPTY_MAP = new Map<string, Expression>();
Expand Down Expand Up @@ -95,7 +95,6 @@ export class ComponentDecoratorHandler implements

private literalCache = new Map<Decorator, ts.ObjectLiteralExpression>();
private elementSchemaRegistry = new DomElementSchemaRegistry();
private typeCheckScopes = new TypeCheckScopes(this.scopeReader, this.metaReader);

/**
* During the asynchronous preanalyze phase, it's necessary to parse the template to extract
Expand Down Expand Up @@ -424,15 +423,36 @@ export class ComponentDecoratorHandler implements
return;
}

const scope = this.typeCheckScopes.getTypeCheckScope(node);
const matcher = new SelectorMatcher<DirectiveMeta>();
const pipes = new Map<string, Reference<ClassDeclaration<ts.ClassDeclaration>>>();
let schemas: SchemaMetadata[] = [];

const scope = this.scopeReader.getScopeForComponent(node);
if (scope === 'error') {
// Don't type-check components that had errors in their scopes.
return;
}

const binder = new R3TargetBinder(scope.matcher);
if (scope !== null) {
for (const meta of scope.compilation.directives) {
if (meta.selector !== null) {
const extMeta = flattenInheritedDirectiveMetadata(this.metaReader, meta.ref);
matcher.addSelectables(CssSelector.parse(meta.selector), extMeta);
}
}
for (const {name, ref} of scope.compilation.pipes) {
if (!ts.isClassDeclaration(ref.node)) {
throw new Error(`Unexpected non-class declaration ${
ts.SyntaxKind[ref.node.kind]} for pipe ${ref.debugName}`);
}
pipes.set(name, ref as Reference<ClassDeclaration<ts.ClassDeclaration>>);
}
schemas = scope.schemas;
}

const binder = new R3TargetBinder(matcher);
ctx.addTemplate(
new Reference(node), binder, meta.template.diagNodes, scope.pipes, scope.schemas,
new Reference(node), binder, meta.template.diagNodes, pipes, schemas,
meta.template.sourceMapping, meta.template.file);
}

Expand Down Expand Up @@ -475,58 +495,45 @@ export class ComponentDecoratorHandler implements
// Set up the R3TargetBinder, as well as a 'directives' array and a 'pipes' map that are later
// fed to the TemplateDefinitionBuilder. First, a SelectorMatcher is constructed to match
// directives that are in scope.
type MatchedDirective = DirectiveMeta&{selector: string};
const matcher = new SelectorMatcher<MatchedDirective>();
const matcher = new SelectorMatcher<DirectiveMeta&{expression: Expression}>();
const directives: {selector: string, expression: Expression}[] = [];

for (const dir of scope.compilation.directives) {
if (dir.selector !== null) {
matcher.addSelectables(CssSelector.parse(dir.selector), dir as MatchedDirective);
const {ref, selector} = dir;
if (selector !== null) {
const expression = this.refEmitter.emit(ref, context);
directives.push({selector, expression});
matcher.addSelectables(CssSelector.parse(selector), {...dir, expression});
}
}
const pipes = new Map<string, Reference<ClassDeclaration>>();
const pipes = new Map<string, Expression>();
for (const pipe of scope.compilation.pipes) {
pipes.set(pipe.name, pipe.ref);
pipes.set(pipe.name, this.refEmitter.emit(pipe.ref, context));
}

// Next, the component template AST is bound using the R3TargetBinder. This produces a
// Next, the component template AST is bound using the R3TargetBinder. This produces an
// BoundTarget, which is similar to a ts.TypeChecker.
const binder = new R3TargetBinder(matcher);
const bound = binder.bind({template: metadata.template.nodes});

// The BoundTarget knows which directives and pipes matched the template.
const usedDirectives = bound.getUsedDirectives().map(directive => {
return {
selector: directive.selector,
expression: this.refEmitter.emit(directive.ref, context),
};
});

const usedPipes: {pipeName: string, expression: Expression}[] = [];
for (const pipeName of bound.getUsedPipes()) {
if (!pipes.has(pipeName)) {
continue;
}
const pipe = pipes.get(pipeName)!;
usedPipes.push({
pipeName,
expression: this.refEmitter.emit(pipe, context),
});
}
const usedDirectives = bound.getUsedDirectives();
const usedPipes = bound.getUsedPipes().map(name => pipes.get(name)!);

// Scan through the directives/pipes actually used in the template and check whether any
// import which needs to be generated would create a cycle.
const cycleDetected =
usedDirectives.some(dir => this._isCyclicImport(dir.expression, context)) ||
usedPipes.some(pipe => this._isCyclicImport(pipe.expression, context));
usedPipes.some(pipe => this._isCyclicImport(pipe, context));

if (!cycleDetected) {
// No cycle was detected. Record the imports that need to be created in the cycle detector
// so that future cyclic import checks consider their production.
for (const {expression} of usedDirectives) {
this._recordSyntheticImport(expression, context);
}
for (const {expression} of usedPipes) {
this._recordSyntheticImport(expression, context);
for (const pipe of usedPipes) {
this._recordSyntheticImport(pipe, context);
}

// Check whether the directive/pipe arrays in ɵcmp need to be wrapped in closures.
Expand All @@ -535,11 +542,16 @@ export class ComponentDecoratorHandler implements
const wrapDirectivesAndPipesInClosure =
usedDirectives.some(
dir => isExpressionForwardReference(dir.expression, node.name, context)) ||
usedPipes.some(
pipe => isExpressionForwardReference(pipe.expression, node.name, context));

data.directives = usedDirectives;
data.pipes = new Map(usedPipes.map(pipe => [pipe.pipeName, pipe.expression]));
usedPipes.some(pipe => isExpressionForwardReference(pipe, node.name, context));

// Actual compilation still uses the full scope, not the narrowed scope determined by
// R3TargetBinder. This is a hedge against potential issues with the R3TargetBinder - right
// now the TemplateDefinitionBuilder is the "source of truth" for which directives/pipes are
// actually used (though the two should agree perfectly).
//
// TODO(alxhub): switch TemplateDefinitionBuilder over to using R3TargetBinder directly.
data.directives = directives;
data.pipes = pipes;
data.wrapDirectivesAndPipesInClosure = wrapDirectivesAndPipesInClosure;
} else {
// Declaring the directiveDefs/pipeDefs arrays directly would require imports that would
Expand Down
105 changes: 0 additions & 105 deletions packages/compiler-cli/src/ngtsc/annotations/src/typecheck_scopes.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/compiler-cli/src/ngtsc/metadata/index.ts
Expand Up @@ -8,7 +8,6 @@

export * from './src/api';
export {DtsMetadataReader} from './src/dts';
export {flattenInheritedDirectiveMetadata} from './src/inheritance';
export {CompoundMetadataRegistry, LocalMetadataRegistry, InjectableClassRegistry} from './src/registry';
export {extractDirectiveTypeCheckMeta, CompoundMetadataReader} from './src/util';
export {BindingPropertyName, ClassPropertyMapping, ClassPropertyName, InputOrOutput} from './src/property_mapping';
3 changes: 0 additions & 3 deletions packages/compiler-cli/src/ngtsc/metadata/src/inheritance.ts
Expand Up @@ -26,9 +26,6 @@ export function flattenInheritedDirectiveMetadata(
if (topMeta === null) {
throw new Error(`Metadata not found for directive: ${dir.debugName}`);
}
if (topMeta.baseClass === null) {
return topMeta;
}

const coercedInputFields = new Set<ClassPropertyName>();
const undeclaredInputFields = new Set<ClassPropertyName>();
Expand Down
4 changes: 1 addition & 3 deletions packages/compiler-cli/src/ngtsc/scope/src/local.ts
Expand Up @@ -26,7 +26,6 @@ export interface LocalNgModuleData {
}

export interface LocalModuleScope extends ExportScope {
ngModule: ClassDeclaration;
compilation: ScopeData;
reexports: Reexport[]|null;
schemas: SchemaMetadata[];
Expand Down Expand Up @@ -434,8 +433,7 @@ export class LocalModuleScopeRegistry implements MetadataRegistry, ComponentScop
}

// Finally, produce the `LocalModuleScope` with both the compilation and export scopes.
const scope: LocalModuleScope = {
ngModule: ngModule.ref.node,
const scope = {
compilation: {
directives: Array.from(compilationDirectives.values()),
pipes: Array.from(compilationPipes.values()),
Expand Down