Skip to content

Commit 99697da

Browse files
JoostKthePunderWoman
authored andcommitted
fix(compiler-cli): only consider used pipes for inline type-check requirement (#46807)
After a bugfix in #46096, the compiler is now better capable of detecting pipes which require an inline type constructor. However, there is an issue in how all pipes are considered when verifying the inline type-ctor requirement: it should only check actually used pipes. Fixes #46747 PR Close #46807
1 parent 4a2c6e3 commit 99697da

File tree

4 files changed

+54
-4
lines changed

4 files changed

+54
-4
lines changed

packages/compiler-cli/src/ngtsc/typecheck/src/context.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,16 @@ export class TypeCheckContextImpl implements TypeCheckContext {
263263
templateDiagnostics,
264264
});
265265

266+
const usedPipes: Reference<ClassDeclaration<ts.ClassDeclaration>>[] = [];
267+
for (const name of boundTarget.getUsedPipes()) {
268+
if (!pipes.has(name)) {
269+
continue;
270+
}
271+
usedPipes.push(pipes.get(name)!);
272+
}
273+
266274
const inliningRequirement =
267-
requiresInlineTypeCheckBlock(ref, shimData.file, pipes, this.reflector);
275+
requiresInlineTypeCheckBlock(ref, shimData.file, usedPipes, this.reflector);
268276

269277
// If inlining is not supported, but is required for either the TCB or one of its directive
270278
// dependencies, then exit here with an error.

packages/compiler-cli/src/ngtsc/typecheck/src/tcb_util.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export enum TcbInliningRequirement {
7373

7474
export function requiresInlineTypeCheckBlock(
7575
ref: Reference<ClassDeclaration<ts.ClassDeclaration>>, env: ReferenceEmitEnvironment,
76-
usedPipes: Map<string, Reference<ClassDeclaration<ts.ClassDeclaration>>>,
76+
usedPipes: Reference<ClassDeclaration<ts.ClassDeclaration>>[],
7777
reflector: ReflectionHost): TcbInliningRequirement {
7878
// In order to qualify for a declared TCB (not inline) two conditions must be met:
7979
// 1) the class must be suitable to be referenced from `env` (e.g. it must be exported)
@@ -85,7 +85,7 @@ export function requiresInlineTypeCheckBlock(
8585
// Condition 2 is false, the class has constrained generic types. It should be checked with an
8686
// inline TCB if possible, but can potentially use fallbacks to avoid inlining if not.
8787
return TcbInliningRequirement.ShouldInlineForGenericBounds;
88-
} else if (Array.from(usedPipes.values()).some(pipeRef => !env.canReferenceType(pipeRef))) {
88+
} else if (usedPipes.some(pipeRef => !env.canReferenceType(pipeRef))) {
8989
// If one of the pipes used by the component is not exported, a non-inline TCB will not be able
9090
// to import it, so this requires an inline TCB.
9191
return TcbInliningRequirement.MustInline;

packages/language-service/test/diagnostic_spec.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,48 @@ describe('getSemanticDiagnostics', () => {
296296
expect(diags.length).toBe(0);
297297
});
298298

299+
it('should exclude unused pipes that would otherwise require an inline TCB', () => {
300+
const files = {
301+
// Declare an external package that exports `MyPipeModule` without also exporting `MyPipe`
302+
// from its public API. This means that `MyPipe` cannot be imported using the package name
303+
// as module specifier.
304+
'node_modules/pipe/pipe.d.ts': `
305+
import {ɵɵDirectiveDeclaration} from '@angular/core';
306+
307+
export declare class MyPipe {
308+
static ɵpipe: ɵɵPipeDeclaration<MyPipe, "myPipe", false>;
309+
}
310+
`,
311+
'node_modules/pipe/index.d.ts': `
312+
import {ɵɵNgModuleDeclaration} from '@angular/core';
313+
import {MyPipe} from './pipe';
314+
315+
export declare class MyPipeModule {
316+
static ɵmod: ɵɵNgModuleDeclaration<MyPipeModule, [typeof MyPipe], never, [typeof MyPipe]>;
317+
}
318+
`,
319+
'app.ts': `
320+
import {Component, NgModule} from '@angular/core';
321+
import {MyPipeModule} from 'pipe';
322+
323+
@Component({
324+
template: 'Simple template that does not use "myPipe"',
325+
})
326+
export class MyComponent {}
327+
328+
@NgModule({
329+
declarations: [MyComponent],
330+
imports: [MyPipeModule],
331+
})
332+
export class MyModule {}
333+
`
334+
};
335+
336+
const project = env.addProject('test', files);
337+
const diags = project.getDiagnosticsForFile('app.ts');
338+
expect(diags.length).toBe(0);
339+
});
340+
299341
it('logs perf tracing', () => {
300342
const files = {
301343
'app.ts': `

packages/language-service/testing/src/project.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export class Project {
6868
const dirPath = fs.dirname(filePath);
6969
fs.ensureDir(dirPath);
7070
fs.writeFile(filePath, contents);
71-
if (projectFilePath.endsWith('.ts')) {
71+
if (projectFilePath.endsWith('.ts') && !projectFilePath.endsWith('.d.ts')) {
7272
entryFiles.push(filePath);
7373
}
7474
}

0 commit comments

Comments
 (0)