From 5cc80dc72f8c0b3de19bd60bf20350dcc461ffd0 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 28 Feb 2025 10:40:48 +0100 Subject: [PATCH] refactor(compiler-cli): change TemplateId terminology (#60191) Renames the `TemplateId` and terminology related to it, because we'll be using it for more than just templates. PR Close #60191 --- .../annotations/component/src/handler.ts | 10 +- .../src/ngtsc/typecheck/api/api.ts | 16 +- .../typecheck/diagnostics/src/diagnostic.ts | 16 +- .../src/ngtsc/typecheck/diagnostics/src/id.ts | 22 +-- .../src/ngtsc/typecheck/src/checker.ts | 20 +-- .../src/ngtsc/typecheck/src/context.ts | 22 +-- .../src/ngtsc/typecheck/src/diagnostics.ts | 6 +- .../src/ngtsc/typecheck/src/dom.ts | 6 +- .../src/ngtsc/typecheck/src/oob.ts | 164 +++++++++--------- .../src/ngtsc/typecheck/src/source.ts | 20 +-- .../src/ngtsc/typecheck/src/tcb_util.ts | 24 +-- .../ngtsc/typecheck/src/type_check_block.ts | 8 +- .../src/ngtsc/typecheck/testing/index.ts | 14 +- 13 files changed, 171 insertions(+), 177 deletions(-) diff --git a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts index c7e12284542..f76b7504945 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts @@ -116,7 +116,7 @@ import { HandlerPrecedence, ResolveResult, } from '../../../transform'; -import {TemplateId, TypeCheckableDirectiveMeta, TypeCheckContext} from '../../../typecheck/api'; +import {TypeCheckId, TypeCheckableDirectiveMeta, TypeCheckContext} from '../../../typecheck/api'; import {ExtendedTemplateChecker} from '../../../typecheck/extended/api'; import {TemplateSemanticsChecker} from '../../../typecheck/template_semantics/api/api'; import {getSourceFile} from '../../../util/src/typescript'; @@ -695,7 +695,8 @@ export class ComponentDecoratorHandler template.errors && template.errors.length > 0 ) { - // Template errors are handled at the type check phase. But we skip this phase in local compilation mode. As a result we need to handle the errors now and add them to the diagnostics. + // Template errors are handled at the type check phase. But we skip this phase in local + // compilation mode. As a result we need to handle the errors now and add them to the diagnostics. if (diagnostics === undefined) { diagnostics = []; } @@ -703,7 +704,10 @@ export class ComponentDecoratorHandler diagnostics.push( ...getTemplateDiagnostics( template.errors, - '' as TemplateId, // Template ID is required as part of the template type check, mainly for mapping the template to its component class. But here we are generating the diagnostic outside of the type check context, and so we skip the template ID. + // Type check ID is required as part of the ype check, mainly for mapping the + // diagnostic back to its source. But here we are generating the diagnostic outside + // of the type check context, and so we skip the template ID. + '' as TypeCheckId, template.sourceMapping, ), ); diff --git a/packages/compiler-cli/src/ngtsc/typecheck/api/api.ts b/packages/compiler-cli/src/ngtsc/typecheck/api/api.ts index ee90e793cad..7ea573900e4 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/api/api.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/api/api.ts @@ -44,7 +44,7 @@ export interface TypeCheckableDirectiveMeta extends DirectiveMeta, DirectiveType rawImports: ts.Expression | null; } -export type TemplateId = string & {__brand: 'TemplateId'}; +export type TypeCheckId = string & {__brand: 'TypeCheckId'}; /** * A `ts.Diagnostic` with additional information about the diagnostic related to template @@ -54,12 +54,12 @@ export interface TemplateDiagnostic extends ts.Diagnostic { /** * The component with the template that resulted in this diagnostic. */ - componentFile: ts.SourceFile; + sourceFile: ts.SourceFile; /** - * The template id of the component that resulted in this diagnostic. + * The type check ID of the directive that resulted in this diagnostic. */ - templateId: TemplateId; + typeCheckId: TypeCheckId; } /** @@ -75,9 +75,9 @@ export interface TypeCheckBlockMetadata { /** * A unique identifier for the class which gave rise to this TCB. * - * This can be used to map errors back to the `ts.ClassDeclaration` for the component. + * This can be used to map errors back to the `ts.ClassDeclaration` for the directive. */ - id: TemplateId; + id: TypeCheckId; /** * Semantic information about the template of the component. @@ -410,10 +410,10 @@ export interface ExternalTemplateSourceMapping { } /** - * A mapping of a TCB template id to a span in the corresponding template source. + * A mapping of a TCB template id to a span in the corresponding source code. */ export interface SourceLocation { - id: TemplateId; + id: TypeCheckId; span: AbsoluteSourceSpan; } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/diagnostics/src/diagnostic.ts b/packages/compiler-cli/src/ngtsc/typecheck/diagnostics/src/diagnostic.ts index 4be9a453418..75b392d7e31 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/diagnostics/src/diagnostic.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/diagnostics/src/diagnostic.ts @@ -14,7 +14,7 @@ import { ExternalTemplateSourceMapping, IndirectTemplateSourceMapping, TemplateDiagnostic, - TemplateId, + TypeCheckId, TemplateSourceMapping, } from '../../api'; @@ -22,7 +22,7 @@ import { * Constructs a `ts.Diagnostic` for a given `ParseSourceSpan` within a template. */ export function makeTemplateDiagnostic( - templateId: TemplateId, + id: TypeCheckId, mapping: TemplateSourceMapping, span: ParseSourceSpan, category: ts.DiagnosticCategory, @@ -59,8 +59,8 @@ export function makeTemplateDiagnostic( category, messageText, file: mapping.node.getSourceFile(), - componentFile: mapping.node.getSourceFile(), - templateId, + sourceFile: mapping.node.getSourceFile(), + typeCheckId: id, start: span.start.offset, length: span.end.offset - span.start.offset, relatedInformation, @@ -107,8 +107,8 @@ export function makeTemplateDiagnostic( code, messageText: addDiagnosticChain(messageText, [failureChain]), file: componentSf, - componentFile: componentSf, - templateId, + sourceFile: componentSf, + typeCheckId: id, // mapping.node represents either the 'template' or 'templateUrl' expression. getStart() // and getEnd() are used because they don't include surrounding whitespace. start: mapping.node.getStart(), @@ -134,8 +134,8 @@ export function makeTemplateDiagnostic( code, messageText, file: sf, - componentFile: componentSf, - templateId, + sourceFile: componentSf, + typeCheckId: id, start: span.start.offset, length: span.end.offset - span.start.offset, // Show a secondary message indicating the component whose template contains the error. diff --git a/packages/compiler-cli/src/ngtsc/typecheck/diagnostics/src/id.ts b/packages/compiler-cli/src/ngtsc/typecheck/diagnostics/src/id.ts index e1ade958237..c3ec8aaca38 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/diagnostics/src/id.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/diagnostics/src/id.ts @@ -9,21 +9,21 @@ import ts from 'typescript'; import {DeclarationNode} from '../../../reflection'; -import {TemplateId} from '../../api'; +import {TypeCheckId} from '../../api'; -const TEMPLATE_ID_MAP = Symbol('ngTemplateId'); +const TYPE_CHECK_ID_MAP = Symbol('TypeCheckId'); -interface HasNextTemplateId { - [TEMPLATE_ID_MAP]: Map; +interface HasNextTypeCheckId { + [TYPE_CHECK_ID_MAP]: Map; } -export function getTemplateId(clazz: DeclarationNode): TemplateId { - const sf = clazz.getSourceFile() as ts.SourceFile & Partial; - if (sf[TEMPLATE_ID_MAP] === undefined) { - sf[TEMPLATE_ID_MAP] = new Map(); +export function getTypeCheckId(clazz: DeclarationNode): TypeCheckId { + const sf = clazz.getSourceFile() as ts.SourceFile & Partial; + if (sf[TYPE_CHECK_ID_MAP] === undefined) { + sf[TYPE_CHECK_ID_MAP] = new Map(); } - if (sf[TEMPLATE_ID_MAP].get(clazz) === undefined) { - sf[TEMPLATE_ID_MAP].set(clazz, `tcb${sf[TEMPLATE_ID_MAP].size + 1}` as TemplateId); + if (sf[TYPE_CHECK_ID_MAP].get(clazz) === undefined) { + sf[TYPE_CHECK_ID_MAP].set(clazz, `tcb${sf[TYPE_CHECK_ID_MAP].size + 1}` as TypeCheckId); } - return sf[TEMPLATE_ID_MAP].get(clazz)!; + return sf[TYPE_CHECK_ID_MAP].get(clazz)!; } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/checker.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/checker.ts index a226d7550bd..48423f17003 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/checker.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/checker.ts @@ -63,7 +63,6 @@ import { Symbol, TcbLocation, TemplateDiagnostic, - TemplateId, TemplateSymbol, TemplateTypeChecker, TypeCheckableDirectiveMeta, @@ -193,9 +192,8 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker { return {data: null, tcb: null, tcbPath: shimPath, tcbIsShim: true}; } - const templateId = fileRecord.sourceManager.getTemplateId(component); + const id = fileRecord.sourceManager.getTypeCheckId(component); const shimRecord = fileRecord.shimData.get(shimPath)!; - const id = fileRecord.sourceManager.getTemplateId(component); const program = this.programDriver.getProgram(); const shimSf = getSourceFileOrNull(program, shimPath); @@ -218,8 +216,8 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker { } let data: TemplateData | null = null; - if (shimRecord.templates.has(templateId)) { - data = shimRecord.templates.get(templateId)!; + if (shimRecord.templates.has(id)) { + data = shimRecord.templates.get(id)!; } return {data, tcb, tcbPath, tcbIsShim: tcbPath === shimPath}; @@ -350,7 +348,7 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker { return []; } - const templateId = fileRecord.sourceManager.getTemplateId(component); + const id = fileRecord.sourceManager.getTypeCheckId(component); const shimRecord = fileRecord.shimData.get(shimPath)!; const typeCheckProgram = this.programDriver.getProgram(); @@ -379,7 +377,7 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker { return diagnostics.filter( (diag: TemplateDiagnostic | null): diag is TemplateDiagnostic => - diag !== null && diag.templateId === templateId, + diag !== null && diag.typeCheckId === id, ); }); } @@ -438,7 +436,7 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker { const sfPath = absoluteFromSourceFile(sf); const shimPath = TypeCheckShimGenerator.shimFor(sfPath); const fileData = this.getFileData(sfPath); - const templateId = fileData.sourceManager.getTemplateId(clazz); + const id = fileData.sourceManager.getTypeCheckId(clazz); fileData.shimData.delete(shimPath); fileData.isComplete = false; @@ -467,12 +465,12 @@ export class TemplateTypeCheckerImpl implements TemplateTypeChecker { ): NgTemplateDiagnostic { const sfPath = absoluteFromSourceFile(clazz.getSourceFile()); const fileRecord = this.state.get(sfPath)!; - const templateId = fileRecord.sourceManager.getTemplateId(clazz); - const mapping = fileRecord.sourceManager.getSourceMapping(templateId); + const id = fileRecord.sourceManager.getTypeCheckId(clazz); + const mapping = fileRecord.sourceManager.getSourceMapping(id); return { ...makeTemplateDiagnostic( - templateId, + id, mapping, sourceSpan, category, diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts index 7e3a26dd5ea..5809289a510 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/context.ts @@ -27,7 +27,7 @@ import {ClassDeclaration, ReflectionHost} from '../../reflection'; import {ImportManager} from '../../translator'; import { TemplateDiagnostic, - TemplateId, + TypeCheckId, TemplateSourceMapping, TypeCheckableDirectiveMeta, TypeCheckBlockMetadata, @@ -67,10 +67,10 @@ export interface ShimTypeCheckingData { hasInlines: boolean; /** - * Map of `TemplateId` to information collected about the template during the template + * Map of `TypeCheckId` to information collected about the template during the template * type-checking process. */ - templates: Map; + templates: Map; } /** @@ -132,9 +132,9 @@ export interface PendingShimData { file: TypeCheckFile; /** - * Map of `TemplateId` to information collected about the template as it's ingested. + * Map of `TypeCheckId` to information collected about the template as it's ingested. */ - templates: Map; + templates: Map; } /** @@ -245,12 +245,12 @@ export class TypeCheckContextImpl implements TypeCheckContext { const fileData = this.dataForFile(ref.node.getSourceFile()); const shimData = this.pendingShimForComponent(ref.node); - const templateId = fileData.sourceManager.getTemplateId(ref.node); + const id = fileData.sourceManager.getTypeCheckId(ref.node); const templateDiagnostics: TemplateDiagnostic[] = []; if (parseErrors !== null) { - templateDiagnostics.push(...getTemplateDiagnostics(parseErrors, templateId, sourceMapping)); + templateDiagnostics.push(...getTemplateDiagnostics(parseErrors, id, sourceMapping)); } const boundTarget = binder.bind({template}); @@ -283,7 +283,7 @@ export class TypeCheckContextImpl implements TypeCheckContext { } } - shimData.templates.set(templateId, { + shimData.templates.set(id, { template, boundTarget, templateDiagnostics, @@ -314,7 +314,7 @@ export class TypeCheckContextImpl implements TypeCheckContext { // and inlining would be required. // Record diagnostics to indicate the issues with this template. - shimData.oobRecorder.requiresInlineTcb(templateId, ref.node); + shimData.oobRecorder.requiresInlineTcb(id, ref.node); // Checking this template would be unsupported, so don't try. this.perf.eventCount(PerfEvent.SkipGenerateTcbNoInline); @@ -537,7 +537,7 @@ export class TypeCheckContextImpl implements TypeCheckContext { this.reflector, this.compilerHost, ), - templates: new Map(), + templates: new Map(), }); } return fileData.shimData.get(shimPath)!; @@ -561,7 +561,7 @@ export class TypeCheckContextImpl implements TypeCheckContext { export function getTemplateDiagnostics( parseErrors: ParseError[], - templateId: TemplateId, + templateId: TypeCheckId, sourceMapping: TemplateSourceMapping, ): TemplateDiagnostic[] { return parseErrors.map((error) => { diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts index 9779078a37c..938449ac970 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/diagnostics.ts @@ -8,7 +8,7 @@ import {AbsoluteSourceSpan, ParseSourceSpan} from '@angular/compiler'; import ts from 'typescript'; -import {TemplateDiagnostic, TemplateId} from '../api'; +import {TemplateDiagnostic, TypeCheckId} from '../api'; import {makeTemplateDiagnostic} from '../diagnostics'; import {getTemplateMapping, TemplateSourceResolver} from './tcb_util'; @@ -58,10 +58,10 @@ export function addParseSpanInfo(node: ts.Node, span: AbsoluteSourceSpan | Parse } /** - * Adds a synthetic comment to the function declaration that contains the template id + * Adds a synthetic comment to the function declaration that contains the type checking ID * of the class declaration. */ -export function addTemplateId(tcb: ts.FunctionDeclaration, id: TemplateId): void { +export function addTypeCheckId(tcb: ts.FunctionDeclaration, id: TypeCheckId): void { ts.addSyntheticLeadingComment(tcb, ts.SyntaxKind.MultiLineCommentTrivia, id, true); } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts index 7973a7b8964..663984166ab 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/dom.ts @@ -15,7 +15,7 @@ import { import ts from 'typescript'; import {ErrorCode, ngErrorCode} from '../../diagnostics'; -import {TemplateDiagnostic, TemplateId} from '../api'; +import {TemplateDiagnostic, TypeCheckId} from '../api'; import {makeTemplateDiagnostic} from '../diagnostics'; import {TemplateSourceResolver} from './tcb_util'; @@ -91,7 +91,7 @@ export class RegistryDomSchemaChecker implements DomSchemaChecker { constructor(private resolver: TemplateSourceResolver) {} checkElement( - id: TemplateId, + id: TypeCheckId, element: TmplAstElement, schemas: SchemaMetadata[], hostIsStandalone: boolean, @@ -130,7 +130,7 @@ export class RegistryDomSchemaChecker implements DomSchemaChecker { } checkProperty( - id: TemplateId, + id: TypeCheckId, element: TmplAstElement, name: string, span: ParseSourceSpan, diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts index b2116ade54b..b79cda13723 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/oob.ts @@ -30,7 +30,7 @@ import ts from 'typescript'; import {ErrorCode, makeDiagnostic, makeRelatedInformation, ngErrorCode} from '../../diagnostics'; import {ClassDeclaration} from '../../reflection'; -import {TemplateDiagnostic, TemplateId} from '../api'; +import {TemplateDiagnostic, TypeCheckId} from '../api'; import {makeTemplateDiagnostic} from '../diagnostics'; import {TemplateSourceResolver} from './tcb_util'; @@ -51,60 +51,56 @@ export interface OutOfBandDiagnosticRecorder { * Reports a `#ref="target"` expression in the template for which a target directive could not be * found. * - * @param templateId the template type-checking ID of the template which contains the broken - * reference. + * @param id the type-checking ID of the template which contains the broken reference. * @param ref the `TmplAstReference` which could not be matched to a directive. */ - missingReferenceTarget(templateId: TemplateId, ref: TmplAstReference): void; + missingReferenceTarget(id: TypeCheckId, ref: TmplAstReference): void; /** * Reports usage of a `| pipe` expression in the template for which the named pipe could not be * found. * - * @param templateId the template type-checking ID of the template which contains the unknown - * pipe. + * @param id the type-checking ID of the template which contains the unknown pipe. * @param ast the `BindingPipe` invocation of the pipe which could not be found. */ - missingPipe(templateId: TemplateId, ast: BindingPipe): void; + missingPipe(id: TypeCheckId, ast: BindingPipe): void; /** * Reports usage of a pipe imported via `@Component.deferredImports` outside * of a `@defer` block in a template. * - * @param templateId the template type-checking ID of the template which contains the unknown - * pipe. + * @param id the type-checking ID of the template which contains the unknown pipe. * @param ast the `BindingPipe` invocation of the pipe which could not be found. */ - deferredPipeUsedEagerly(templateId: TemplateId, ast: BindingPipe): void; + deferredPipeUsedEagerly(id: TypeCheckId, ast: BindingPipe): void; /** * Reports usage of a component/directive imported via `@Component.deferredImports` outside * of a `@defer` block in a template. * - * @param templateId the template type-checking ID of the template which contains the unknown - * pipe. + * @param id the type-checking ID of the template which contains the unknown pipe. * @param element the element which hosts a component that was defer-loaded. */ - deferredComponentUsedEagerly(templateId: TemplateId, element: TmplAstElement): void; + deferredComponentUsedEagerly(id: TypeCheckId, element: TmplAstElement): void; /** * Reports a duplicate declaration of a template variable. * - * @param templateId the template type-checking ID of the template which contains the duplicate + * @param id the type-checking ID of the template which contains the duplicate * declaration. * @param variable the `TmplAstVariable` which duplicates a previously declared variable. * @param firstDecl the first variable declaration which uses the same name as `variable`. */ duplicateTemplateVar( - templateId: TemplateId, + id: TypeCheckId, variable: TmplAstVariable, firstDecl: TmplAstVariable, ): void; - requiresInlineTcb(templateId: TemplateId, node: ClassDeclaration): void; + requiresInlineTcb(id: TypeCheckId, node: ClassDeclaration): void; requiresInlineTypeConstructors( - templateId: TemplateId, + id: TypeCheckId, node: ClassDeclaration, directives: ClassDeclaration[], ): void; @@ -113,13 +109,13 @@ export interface OutOfBandDiagnosticRecorder { * Report a warning when structural directives support context guards, but the current * type-checking configuration prohibits their usage. */ - suboptimalTypeInference(templateId: TemplateId, variables: TmplAstVariable[]): void; + suboptimalTypeInference(id: TypeCheckId, variables: TmplAstVariable[]): void; /** * Reports a split two way binding error message. */ splitTwoWayBinding( - templateId: TemplateId, + id: TypeCheckId, input: TmplAstBoundAttribute, output: TmplAstBoundEvent, inputConsumer: ClassDeclaration, @@ -128,7 +124,7 @@ export interface OutOfBandDiagnosticRecorder { /** Reports required inputs that haven't been bound. */ missingRequiredInputs( - templateId: TemplateId, + id: TypeCheckId, element: TmplAstElement | TmplAstTemplate, directiveName: string, isComponent: boolean, @@ -139,7 +135,7 @@ export interface OutOfBandDiagnosticRecorder { * Reports accesses of properties that aren't available in a `for` block's tracking expression. */ illegalForLoopTrackAccess( - templateId: TemplateId, + id: TypeCheckId, block: TmplAstForLoopBlock, access: PropertyRead, ): void; @@ -148,7 +144,7 @@ export interface OutOfBandDiagnosticRecorder { * Reports deferred triggers that cannot access the element they're referring to. */ inaccessibleDeferredTriggerElement( - templateId: TemplateId, + id: TypeCheckId, trigger: | TmplAstHoverDeferredTrigger | TmplAstInteractionDeferredTrigger @@ -159,7 +155,7 @@ export interface OutOfBandDiagnosticRecorder { * Reports cases where control flow nodes prevent content projection. */ controlFlowPreventingContentProjection( - templateId: TemplateId, + id: TypeCheckId, category: ts.DiagnosticCategory, projectionNode: TmplAstElement | TmplAstTemplate, componentName: string, @@ -174,25 +170,21 @@ export interface OutOfBandDiagnosticRecorder { /** Reports cases where users are writing to `@let` declarations. */ illegalWriteToLetDeclaration( - templateId: TemplateId, + id: TypeCheckId, node: PropertyWrite, target: TmplAstLetDeclaration, ): void; /** Reports cases where users are accessing an `@let` before it is defined.. */ - letUsedBeforeDefinition( - templateId: TemplateId, - node: PropertyRead, - target: TmplAstLetDeclaration, - ): void; + letUsedBeforeDefinition(id: TypeCheckId, node: PropertyRead, target: TmplAstLetDeclaration): void; /** * Reports a `@let` declaration that conflicts with another symbol in the same scope. * - * @param templateId the template type-checking ID of the template which contains the declaration. + * @param id the type-checking ID of the template which contains the declaration. * @param current the `TmplAstLetDeclaration` which is invalid. */ - conflictingDeclaration(templateId: TemplateId, current: TmplAstLetDeclaration): void; + conflictingDeclaration(id: TypeCheckId, current: TmplAstLetDeclaration): void; } export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecorder { @@ -210,14 +202,14 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor return this._diagnostics; } - missingReferenceTarget(templateId: TemplateId, ref: TmplAstReference): void { - const mapping = this.resolver.getSourceMapping(templateId); + missingReferenceTarget(id: TypeCheckId, ref: TmplAstReference): void { + const mapping = this.resolver.getSourceMapping(id); const value = ref.value.trim(); const errorMsg = `No directive found with exportAs '${value}'.`; this._diagnostics.push( makeTemplateDiagnostic( - templateId, + id, mapping, ref.valueSpan || ref.sourceSpan, ts.DiagnosticCategory.Error, @@ -227,15 +219,15 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor ); } - missingPipe(templateId: TemplateId, ast: BindingPipe): void { + missingPipe(id: TypeCheckId, ast: BindingPipe): void { if (this.recordedPipes.has(ast)) { return; } - const mapping = this.resolver.getSourceMapping(templateId); + const mapping = this.resolver.getSourceMapping(id); const errorMsg = `No pipe found with name '${ast.name}'.`; - const sourceSpan = this.resolver.toParseSourceSpan(templateId, ast.nameSpan); + const sourceSpan = this.resolver.toParseSourceSpan(id, ast.nameSpan); if (sourceSpan === null) { throw new Error( `Assertion failure: no SourceLocation found for usage of pipe '${ast.name}'.`, @@ -243,7 +235,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } this._diagnostics.push( makeTemplateDiagnostic( - templateId, + id, mapping, sourceSpan, ts.DiagnosticCategory.Error, @@ -254,19 +246,19 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor this.recordedPipes.add(ast); } - deferredPipeUsedEagerly(templateId: TemplateId, ast: BindingPipe): void { + deferredPipeUsedEagerly(id: TypeCheckId, ast: BindingPipe): void { if (this.recordedPipes.has(ast)) { return; } - const mapping = this.resolver.getSourceMapping(templateId); + const mapping = this.resolver.getSourceMapping(id); const errorMsg = `Pipe '${ast.name}' was imported via \`@Component.deferredImports\`, ` + `but was used outside of a \`@defer\` block in a template. To fix this, either ` + `use the '${ast.name}' pipe inside of a \`@defer\` block or import this dependency ` + `using the \`@Component.imports\` field.`; - const sourceSpan = this.resolver.toParseSourceSpan(templateId, ast.nameSpan); + const sourceSpan = this.resolver.toParseSourceSpan(id, ast.nameSpan); if (sourceSpan === null) { throw new Error( `Assertion failure: no SourceLocation found for usage of pipe '${ast.name}'.`, @@ -274,7 +266,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } this._diagnostics.push( makeTemplateDiagnostic( - templateId, + id, mapping, sourceSpan, ts.DiagnosticCategory.Error, @@ -285,8 +277,8 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor this.recordedPipes.add(ast); } - deferredComponentUsedEagerly(templateId: TemplateId, element: TmplAstElement): void { - const mapping = this.resolver.getSourceMapping(templateId); + deferredComponentUsedEagerly(id: TypeCheckId, element: TmplAstElement): void { + const mapping = this.resolver.getSourceMapping(id); const errorMsg = `Element '${element.name}' contains a component or a directive that ` + `was imported via \`@Component.deferredImports\`, but the element itself is located ` + @@ -296,7 +288,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor const {start, end} = element.startSourceSpan; const absoluteSourceSpan = new AbsoluteSourceSpan(start.offset, end.offset); - const sourceSpan = this.resolver.toParseSourceSpan(templateId, absoluteSourceSpan); + const sourceSpan = this.resolver.toParseSourceSpan(id, absoluteSourceSpan); if (sourceSpan === null) { throw new Error( `Assertion failure: no SourceLocation found for usage of pipe '${element.name}'.`, @@ -304,7 +296,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } this._diagnostics.push( makeTemplateDiagnostic( - templateId, + id, mapping, sourceSpan, ts.DiagnosticCategory.Error, @@ -315,11 +307,11 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } duplicateTemplateVar( - templateId: TemplateId, + id: TypeCheckId, variable: TmplAstVariable, firstDecl: TmplAstVariable, ): void { - const mapping = this.resolver.getSourceMapping(templateId); + const mapping = this.resolver.getSourceMapping(id); const errorMsg = `Cannot redeclare variable '${variable.name}' as it was previously declared elsewhere for the same template.`; // The allocation of the error here is pretty useless for variables declared in microsyntax, @@ -329,7 +321,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor // TODO(alxhub): allocate to a tighter span once one is available. this._diagnostics.push( makeTemplateDiagnostic( - templateId, + id, mapping, variable.sourceSpan, ts.DiagnosticCategory.Error, @@ -347,10 +339,10 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor ); } - requiresInlineTcb(templateId: TemplateId, node: ClassDeclaration): void { + requiresInlineTcb(id: TypeCheckId, node: ClassDeclaration): void { this._diagnostics.push( makeInlineDiagnostic( - templateId, + id, ErrorCode.INLINE_TCB_REQUIRED, node.name, `This component requires inline template type-checking, which is not supported by the current environment.`, @@ -359,7 +351,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } requiresInlineTypeConstructors( - templateId: TemplateId, + id: TypeCheckId, node: ClassDeclaration, directives: ClassDeclaration[], ): void { @@ -372,7 +364,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor this._diagnostics.push( makeInlineDiagnostic( - templateId, + id, ErrorCode.INLINE_TYPE_CTOR_REQUIRED, node.name, message, @@ -383,8 +375,8 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor ); } - suboptimalTypeInference(templateId: TemplateId, variables: TmplAstVariable[]): void { - const mapping = this.resolver.getSourceMapping(templateId); + suboptimalTypeInference(id: TypeCheckId, variables: TmplAstVariable[]): void { + const mapping = this.resolver.getSourceMapping(id); // Select one of the template variables that's most suitable for reporting the diagnostic. Any // variable will do, but prefer one bound to the context's $implicit if present. @@ -409,7 +401,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor this._diagnostics.push( makeTemplateDiagnostic( - templateId, + id, mapping, diagnosticVar.keySpan, ts.DiagnosticCategory.Suggestion, @@ -420,13 +412,13 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } splitTwoWayBinding( - templateId: TemplateId, + id: TypeCheckId, input: TmplAstBoundAttribute, output: TmplAstBoundEvent, inputConsumer: ClassDeclaration, outputConsumer: ClassDeclaration | TmplAstElement, ): void { - const mapping = this.resolver.getSourceMapping(templateId); + const mapping = this.resolver.getSourceMapping(id); const errorMsg = `The property and event halves of the two-way binding '${input.name}' are not bound to the same target. Find more at https://angular.dev/guide/templates/two-way-binding#how-two-way-binding-works`; @@ -462,7 +454,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor this._diagnostics.push( makeTemplateDiagnostic( - templateId, + id, mapping, input.keySpan, ts.DiagnosticCategory.Error, @@ -474,7 +466,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } missingRequiredInputs( - templateId: TemplateId, + id: TypeCheckId, element: TmplAstElement | TmplAstTemplate, directiveName: string, isComponent: boolean, @@ -488,8 +480,8 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor this._diagnostics.push( makeTemplateDiagnostic( - templateId, - this.resolver.getSourceMapping(templateId), + id, + this.resolver.getSourceMapping(id), element.startSourceSpan, ts.DiagnosticCategory.Error, ngErrorCode(ErrorCode.MISSING_REQUIRED_INPUTS), @@ -499,11 +491,11 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } illegalForLoopTrackAccess( - templateId: TemplateId, + id: TypeCheckId, block: TmplAstForLoopBlock, access: PropertyRead, ): void { - const sourceSpan = this.resolver.toParseSourceSpan(templateId, access.sourceSpan); + const sourceSpan = this.resolver.toParseSourceSpan(id, access.sourceSpan); if (sourceSpan === null) { throw new Error(`Assertion failure: no SourceLocation found for property read.`); } @@ -517,8 +509,8 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor this._diagnostics.push( makeTemplateDiagnostic( - templateId, - this.resolver.getSourceMapping(templateId), + id, + this.resolver.getSourceMapping(id), sourceSpan, ts.DiagnosticCategory.Error, ngErrorCode(ErrorCode.ILLEGAL_FOR_LOOP_TRACK_ACCESS), @@ -528,7 +520,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } inaccessibleDeferredTriggerElement( - templateId: TemplateId, + id: TypeCheckId, trigger: | TmplAstHoverDeferredTrigger | TmplAstInteractionDeferredTrigger @@ -549,8 +541,8 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor this._diagnostics.push( makeTemplateDiagnostic( - templateId, - this.resolver.getSourceMapping(templateId), + id, + this.resolver.getSourceMapping(id), trigger.sourceSpan, ts.DiagnosticCategory.Error, ngErrorCode(ErrorCode.INACCESSIBLE_DEFERRED_TRIGGER_ELEMENT), @@ -560,7 +552,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } controlFlowPreventingContentProjection( - templateId: TemplateId, + id: TypeCheckId, category: ts.DiagnosticCategory, projectionNode: TmplAstElement | TmplAstTemplate, componentName: string, @@ -595,8 +587,8 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor this._diagnostics.push( makeTemplateDiagnostic( - templateId, - this.resolver.getSourceMapping(templateId), + id, + this.resolver.getSourceMapping(id), projectionNode.startSourceSpan, category, ngErrorCode(ErrorCode.CONTROL_FLOW_PREVENTING_CONTENT_PROJECTION), @@ -606,19 +598,19 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } illegalWriteToLetDeclaration( - templateId: TemplateId, + id: TypeCheckId, node: PropertyWrite, target: TmplAstLetDeclaration, ): void { - const sourceSpan = this.resolver.toParseSourceSpan(templateId, node.sourceSpan); + const sourceSpan = this.resolver.toParseSourceSpan(id, node.sourceSpan); if (sourceSpan === null) { throw new Error(`Assertion failure: no SourceLocation found for property write.`); } this._diagnostics.push( makeTemplateDiagnostic( - templateId, - this.resolver.getSourceMapping(templateId), + id, + this.resolver.getSourceMapping(id), sourceSpan, ts.DiagnosticCategory.Error, ngErrorCode(ErrorCode.ILLEGAL_LET_WRITE), @@ -628,19 +620,19 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } letUsedBeforeDefinition( - templateId: TemplateId, + id: TypeCheckId, node: PropertyRead, target: TmplAstLetDeclaration, ): void { - const sourceSpan = this.resolver.toParseSourceSpan(templateId, node.sourceSpan); + const sourceSpan = this.resolver.toParseSourceSpan(id, node.sourceSpan); if (sourceSpan === null) { throw new Error(`Assertion failure: no SourceLocation found for property read.`); } this._diagnostics.push( makeTemplateDiagnostic( - templateId, - this.resolver.getSourceMapping(templateId), + id, + this.resolver.getSourceMapping(id), sourceSpan, ts.DiagnosticCategory.Error, ngErrorCode(ErrorCode.LET_USED_BEFORE_DEFINITION), @@ -649,13 +641,13 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor ); } - conflictingDeclaration(templateId: TemplateId, decl: TmplAstLetDeclaration): void { - const mapping = this.resolver.getSourceMapping(templateId); + conflictingDeclaration(id: TypeCheckId, decl: TmplAstLetDeclaration): void { + const mapping = this.resolver.getSourceMapping(id); const errorMsg = `Cannot declare @let called '${decl.name}' as there is another symbol in the template with the same name.`; this._diagnostics.push( makeTemplateDiagnostic( - templateId, + id, mapping, decl.sourceSpan, ts.DiagnosticCategory.Error, @@ -667,7 +659,7 @@ export class OutOfBandDiagnosticRecorderImpl implements OutOfBandDiagnosticRecor } function makeInlineDiagnostic( - templateId: TemplateId, + id: TypeCheckId, code: ErrorCode.INLINE_TCB_REQUIRED | ErrorCode.INLINE_TYPE_CTOR_REQUIRED, node: ts.Node, messageText: string | ts.DiagnosticMessageChain, @@ -675,7 +667,7 @@ function makeInlineDiagnostic( ): TemplateDiagnostic { return { ...makeDiagnostic(code, node, messageText, relatedInformation), - componentFile: node.getSourceFile(), - templateId, + sourceFile: node.getSourceFile(), + typeCheckId: id, }; } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/source.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/source.ts index 6959ef1df15..3fbfb4e7a4e 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/source.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/source.ts @@ -14,8 +14,8 @@ import { } from '@angular/compiler'; import ts from 'typescript'; -import {TemplateId, TemplateSourceMapping} from '../api'; -import {getTemplateId} from '../diagnostics'; +import {TypeCheckId, TemplateSourceMapping} from '../api'; +import {getTypeCheckId} from '../diagnostics'; import {computeLineStartsMap, getLineAndCharacterFromPosition} from './line_mappings'; import {TemplateSourceResolver} from './tcb_util'; @@ -53,7 +53,7 @@ export class TemplateSource { } /** - * Assigns IDs to templates and keeps track of their origins. + * Assigns IDs for type checking and keeps track of their origins. * * Implements `TemplateSourceResolver` to resolve the source of a template based on these IDs. */ @@ -63,30 +63,30 @@ export class TemplateSourceManager implements TemplateSourceResolver { * attached to a TCB's function declaration as leading trivia. This enables translation of * diagnostics produced for TCB code to their source location in the template. */ - private templateSources = new Map(); + private templateSources = new Map(); - getTemplateId(node: ts.ClassDeclaration): TemplateId { - return getTemplateId(node); + getTypeCheckId(node: ts.ClassDeclaration): TypeCheckId { + return getTypeCheckId(node); } captureSource( node: ts.ClassDeclaration, mapping: TemplateSourceMapping, file: ParseSourceFile, - ): TemplateId { - const id = getTemplateId(node); + ): TypeCheckId { + const id = getTypeCheckId(node); this.templateSources.set(id, new TemplateSource(mapping, file)); return id; } - getSourceMapping(id: TemplateId): TemplateSourceMapping { + getSourceMapping(id: TypeCheckId): TemplateSourceMapping { if (!this.templateSources.has(id)) { throw new Error(`Unexpected unknown template ID: ${id}`); } return this.templateSources.get(id)!.mapping; } - toParseSourceSpan(id: TemplateId, span: AbsoluteSourceSpan): ParseSourceSpan | null { + toParseSourceSpan(id: TypeCheckId, span: AbsoluteSourceSpan): ParseSourceSpan | null { if (!this.templateSources.has(id)) { return null; } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/tcb_util.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/tcb_util.ts index 3230311bab7..2c02897a7e1 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/tcb_util.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/tcb_util.ts @@ -12,7 +12,7 @@ import ts from 'typescript'; import {ClassDeclaration, ReflectionHost} from '../../../../src/ngtsc/reflection'; import {Reference} from '../../imports'; import {getTokenAtPosition} from '../../util/src/typescript'; -import {FullTemplateMapping, SourceLocation, TemplateId, TemplateSourceMapping} from '../api'; +import {FullTemplateMapping, SourceLocation, TypeCheckId, TemplateSourceMapping} from '../api'; import {hasIgnoreForDiagnosticsMarker, readSpanComment} from './comments'; import {ReferenceEmitEnvironment} from './reference_emit_environment'; @@ -37,24 +37,24 @@ const TCB_FILE_IMPORT_GRAPH_PREPARE_IDENTIFIERS = [ ]; /** - * Adapter interface which allows the template type-checking diagnostics code to interpret offsets + * Adapter interface which allows the directive type-checking diagnostics code to interpret offsets * in a TCB and map them back to original locations in the template. */ export interface TemplateSourceResolver { - getTemplateId(node: ts.ClassDeclaration): TemplateId; + getTypeCheckId(node: ts.ClassDeclaration): TypeCheckId; /** - * For the given template id, retrieve the original source mapping which describes how the offsets - * in the template should be interpreted. + * For the given type checking id, retrieve the original source mapping which describes how the + * offsets in the template should be interpreted. */ - getSourceMapping(id: TemplateId): TemplateSourceMapping; + getSourceMapping(id: TypeCheckId): TemplateSourceMapping; /** - * Convert an absolute source span associated with the given template id into a full + * Convert an absolute source span associated with the given type checking id into a full * `ParseSourceSpan`. The returned parse span has line and column numbers in addition to only - * absolute offsets and gives access to the original template source. + * absolute offsets and gives access to the original source code. */ - toParseSourceSpan(id: TemplateId, span: AbsoluteSourceSpan): ParseSourceSpan | null; + toParseSourceSpan(id: TypeCheckId, span: AbsoluteSourceSpan): ParseSourceSpan | null; } /** @@ -131,7 +131,7 @@ export function getTemplateMapping( export function findTypeCheckBlock( file: ts.SourceFile, - id: TemplateId, + id: TypeCheckId, isDiagnosticRequest: boolean, ): ts.Node | null { for (const stmt of file.statements) { @@ -181,7 +181,7 @@ function getTemplateId( node: ts.Node, sourceFile: ts.SourceFile, isDiagnosticRequest: boolean, -): TemplateId | null { +): TypeCheckId | null { // Walk up to the function declaration of the TCB, the file information is attached there. while (!ts.isFunctionDeclaration(node)) { if (hasIgnoreForDiagnosticsMarker(node, sourceFile) && isDiagnosticRequest) { @@ -204,7 +204,7 @@ function getTemplateId( } const commentText = sourceFile.text.substring(pos + 2, end - 2); return commentText; - }) as TemplateId) || null + }) as TypeCheckId) || null ); } diff --git a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts index 0f50f8aeef6..d3de7f982f7 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/src/type_check_block.ts @@ -58,12 +58,12 @@ import ts from 'typescript'; import {Reference} from '../../imports'; import {BindingPropertyName, ClassPropertyName, PipeMeta} from '../../metadata'; import {ClassDeclaration} from '../../reflection'; -import {TemplateId, TypeCheckableDirectiveMeta, TypeCheckBlockMetadata} from '../api'; +import {TypeCheckId, TypeCheckableDirectiveMeta, TypeCheckBlockMetadata} from '../api'; import {addExpressionIdentifier, ExpressionIdentifier, markIgnoreDiagnostics} from './comments'; import { addParseSpanInfo, - addTemplateId, + addTypeCheckId, wrapForDiagnostics, wrapForTypeChecker, } from './diagnostics'; @@ -213,7 +213,7 @@ export function generateTypeCheckBlock( /* type */ undefined, /* body */ body, ); - addTemplateId(fnDecl, meta.id); + addTypeCheckId(fnDecl, meta.id); return fnDecl; } @@ -1934,7 +1934,7 @@ export class Context { readonly env: Environment, readonly domSchemaChecker: DomSchemaChecker, readonly oobRecorder: OutOfBandDiagnosticRecorder, - readonly id: TemplateId, + readonly id: TypeCheckId, readonly boundTarget: BoundTarget, private pipes: Map, readonly schemas: SchemaMetadata[], diff --git a/packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts b/packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts index 5d1c9e2bca1..d22532ac340 100644 --- a/packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts +++ b/packages/compiler-cli/src/ngtsc/typecheck/testing/index.ts @@ -79,7 +79,7 @@ import { TypeCheckContext, } from '../api'; import { - TemplateId, + TypeCheckId, TemplateSourceMapping, TypeCheckableDirectiveMeta, TypeCheckBlockMetadata, @@ -388,7 +388,7 @@ export function tcb( const binder = new R3TargetBinder(matcher); const boundTarget = binder.bind({template: nodes}); - const id = 'tcb' as TemplateId; + const id = 'tcb' as TypeCheckId; const meta: TypeCheckBlockMetadata = { id, boundTarget, @@ -1039,8 +1039,8 @@ export class NoopOobRecorder implements OutOfBandDiagnosticRecorder { } missingReferenceTarget(): void {} missingPipe(): void {} - deferredPipeUsedEagerly(templateId: TemplateId, ast: BindingPipe): void {} - deferredComponentUsedEagerly(templateId: TemplateId, element: TmplAstElement): void {} + deferredPipeUsedEagerly(id: TypeCheckId, ast: BindingPipe): void {} + deferredComponentUsedEagerly(id: TypeCheckId, element: TmplAstElement): void {} duplicateTemplateVar(): void {} requiresInlineTcb(): void {} requiresInlineTypeConstructors(): void {} @@ -1051,14 +1051,14 @@ export class NoopOobRecorder implements OutOfBandDiagnosticRecorder { inaccessibleDeferredTriggerElement(): void {} controlFlowPreventingContentProjection(): void {} illegalWriteToLetDeclaration( - templateId: TemplateId, + id: TypeCheckId, node: PropertyWrite, target: TmplAstLetDeclaration, ): void {} letUsedBeforeDefinition( - templateId: TemplateId, + id: TypeCheckId, node: PropertyRead, target: TmplAstLetDeclaration, ): void {} - conflictingDeclaration(templateId: TemplateId, current: TmplAstLetDeclaration): void {} + conflictingDeclaration(id: TypeCheckId, current: TmplAstLetDeclaration): void {} }