From 9eb82749914064c1a2fb38f2768ecd6b9be74a29 Mon Sep 17 00:00:00 2001 From: JoostK Date: Tue, 19 Mar 2019 21:22:03 +0100 Subject: [PATCH] fix(ivy): emit generic type arguments in Pipe metadata (#29403) Previously, only directives and services with generic type parameters would emit `any` as generic type when emitting Ivy metadata into .d.ts files. Pipes can also have generic type parameters but did not emit `any` for all type parameters, resulting in the omission of those parameters which causes compilation errors. This commit adds support for pipes with generic type arguments and emits `any` as generic type in the Ivy metadata. Fixes #29400 PR Close #29403 --- .../src/ngtsc/annotations/src/pipe.ts | 2 +- .../compiler-cli/test/ngtsc/ngtsc_spec.ts | 20 ++++++++++ .../compiler/src/compiler_facade_interface.ts | 1 + packages/compiler/src/jit_compiler_facade.ts | 1 + .../compiler/src/render3/r3_pipe_compiler.ts | 40 ++++++++++++++----- .../src/compiler/compiler_facade_interface.ts | 1 + packages/core/src/render3/jit/pipe.ts | 1 + 7 files changed, 55 insertions(+), 11 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts index 6dbe910b87..8e04403391 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts @@ -98,7 +98,7 @@ export class PipeDecoratorHandler implements DecoratorHandler { expect(jsContents).toContain('return new (t || TestPipe)(i0.ɵdirectiveInject(Dep));'); }); + it('should compile Pipes with generic types', () => { + env.tsconfig(); + env.write('test.ts', ` + import {Pipe} from '@angular/core'; + + @Pipe({ + name: 'test-pipe', + }) + export class TestPipe {} + `); + + env.driveMain(); + + const jsContents = env.getContents('test.js'); + expect(jsContents).toContain('TestPipe.ngPipeDef ='); + const dtsContents = env.getContents('test.d.ts'); + expect(dtsContents) + .toContain('static ngPipeDef: i0.ɵPipeDefWithMeta, "test-pipe">;'); + }); + it('should include @Pipes in @NgModule scopes', () => { env.tsconfig(); env.write('test.ts', ` diff --git a/packages/compiler/src/compiler_facade_interface.ts b/packages/compiler/src/compiler_facade_interface.ts index 83945a8546..2f4112afaf 100644 --- a/packages/compiler/src/compiler_facade_interface.ts +++ b/packages/compiler/src/compiler_facade_interface.ts @@ -77,6 +77,7 @@ export interface R3DependencyMetadataFacade { export interface R3PipeMetadataFacade { name: string; type: any; + typeArgumentCount: number; pipeName: string; deps: R3DependencyMetadataFacade[]|null; pure: boolean; diff --git a/packages/compiler/src/jit_compiler_facade.ts b/packages/compiler/src/jit_compiler_facade.ts index 7e50de5311..783870af89 100644 --- a/packages/compiler/src/jit_compiler_facade.ts +++ b/packages/compiler/src/jit_compiler_facade.ts @@ -38,6 +38,7 @@ export class CompilerFacadeImpl implements CompilerFacade { const res = compilePipeFromMetadata({ name: facade.name, type: new WrappedNodeExpr(facade.type), + typeArgumentCount: facade.typeArgumentCount, deps: convertR3DependencyMetadataArray(facade.deps), pipeName: facade.pipeName, pure: facade.pure, diff --git a/packages/compiler/src/render3/r3_pipe_compiler.ts b/packages/compiler/src/render3/r3_pipe_compiler.ts index 2e35262710..5505ccbcbf 100644 --- a/packages/compiler/src/render3/r3_pipe_compiler.ts +++ b/packages/compiler/src/render3/r3_pipe_compiler.ts @@ -14,19 +14,38 @@ import {OutputContext, error} from '../util'; import {R3DependencyMetadata, compileFactoryFunction, dependenciesFromGlobalMetadata} from './r3_factory'; import {Identifiers as R3} from './r3_identifiers'; +import {typeWithParameters} from './util'; export interface R3PipeMetadata { + /** + * Name of the pipe type. + */ name: string; - type: o.Expression; - pipeName: string; - deps: R3DependencyMetadata[]|null; - pure: boolean; -} -export interface R3PipeDef { - expression: o.Expression; - type: o.Type; - statements: o.Statement[]; + /** + * An expression representing a reference to the pipe itself. + */ + type: o.Expression; + + /** + * Number of generic type parameters of the type itself. + */ + typeArgumentCount: number; + + /** + * Name of the pipe. + */ + pipeName: string; + + /** + * Dependencies of the pipe's constructor. + */ + deps: R3DependencyMetadata[]|null; + + /** + * Whether the pipe is marked as pure. + */ + pure: boolean; } export function compilePipeFromMetadata(metadata: R3PipeMetadata) { @@ -51,7 +70,7 @@ export function compilePipeFromMetadata(metadata: R3PipeMetadata) { const expression = o.importExpr(R3.definePipe).callFn([o.literalMap(definitionMapValues)]); const type = new o.ExpressionType(o.importExpr(R3.PipeDefWithMeta, [ - new o.ExpressionType(metadata.type), + typeWithParameters(metadata.type, metadata.typeArgumentCount), new o.ExpressionType(new o.LiteralExpr(metadata.pipeName)), ])); return {expression, type, statements: templateFactory.statements}; @@ -73,6 +92,7 @@ export function compilePipeFromRender2( name, pipeName: pipe.name, type: outputCtx.importExpr(pipe.type.reference), + typeArgumentCount: 0, deps: dependenciesFromGlobalMetadata(pipe.type, outputCtx, reflector), pure: pipe.pure, }; diff --git a/packages/core/src/compiler/compiler_facade_interface.ts b/packages/core/src/compiler/compiler_facade_interface.ts index 7e31746bb0..a010cff02e 100644 --- a/packages/core/src/compiler/compiler_facade_interface.ts +++ b/packages/core/src/compiler/compiler_facade_interface.ts @@ -77,6 +77,7 @@ export interface R3DependencyMetadataFacade { export interface R3PipeMetadataFacade { name: string; type: any; + typeArgumentCount: number; pipeName: string; deps: R3DependencyMetadataFacade[]|null; pure: boolean; diff --git a/packages/core/src/render3/jit/pipe.ts b/packages/core/src/render3/jit/pipe.ts index bf1ea25e92..9fb9401aa4 100644 --- a/packages/core/src/render3/jit/pipe.ts +++ b/packages/core/src/render3/jit/pipe.ts @@ -23,6 +23,7 @@ export function compilePipe(type: Type, meta: Pipe): void { ngPipeDef = getCompilerFacade().compilePipe( angularCoreEnv, `ng://${renderStringify(type)}/ngPipeDef.js`, { type: type, + typeArgumentCount: 0, name: type.name, deps: reflectDependencies(type), pipeName: meta.name,