diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 011cec51ef63b..62516d097b4f3 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -44,6 +44,7 @@ import { declarationNameToString, DeleteExpression, DestructuringAssignment, + DiagnosticArguments, DiagnosticCategory, DiagnosticMessage, DiagnosticRelatedInformation, @@ -556,8 +557,8 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { * If so, the node _must_ be in the current file (as that's the only way anything could have traversed to it to yield it as the error node) * This version of `createDiagnosticForNode` uses the binder's context to account for this, and always yields correct diagnostics even in these situations. */ - function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation { - return createDiagnosticForNodeInSourceFile(getSourceFileOfNode(node) || file, node, message, arg0, arg1, arg2); + function createDiagnosticForNode(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { + return createDiagnosticForNodeInSourceFile(getSourceFileOfNode(node) || file, node, message, ...args); } function bindSourceFile(f: SourceFile, opts: CompilerOptions) { @@ -840,7 +841,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { const declarationName = getNameOfDeclaration(node) || node; forEach(symbol.declarations, (declaration, index) => { const decl = getNameOfDeclaration(declaration) || declaration; - const diag = createDiagnosticForNode(decl, message, messageNeedsName ? getDisplayName(declaration) : undefined); + const diag = messageNeedsName ? createDiagnosticForNode(decl, message, getDisplayName(declaration)) : createDiagnosticForNode(decl, message); file.bindDiagnostics.push( multipleDefaultExports ? addRelatedInfo(diag, createDiagnosticForNode(declarationName, index === 0 ? Diagnostics.Another_export_default_is_here : Diagnostics.and_here)) : diag ); @@ -849,7 +850,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } }); - const diag = createDiagnosticForNode(declarationName, message, messageNeedsName ? getDisplayName(node) : undefined); + const diag = messageNeedsName ? createDiagnosticForNode(declarationName, message, getDisplayName(node)) : createDiagnosticForNode(declarationName, message); file.bindDiagnostics.push(addRelatedInfo(diag, ...relatedInformation)); symbol = createSymbol(SymbolFlags.None, name); @@ -2613,9 +2614,9 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } } - function errorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any) { + function errorOnFirstToken(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments) { const span = getSpanOfTokenAtPosition(file, node.pos); - file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, arg0, arg1, arg2)); + file.bindDiagnostics.push(createFileDiagnostic(file, span.start, span.length, message, ...args)); } function errorOrSuggestionOnNode(isError: boolean, node: Node, message: DiagnosticMessage): void { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4a3c0b233b8e3..c89a926649394 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33,7 +33,6 @@ import { BigIntLiteral, BigIntLiteralType, BinaryExpression, - BinaryOperator, BinaryOperatorToken, binarySearch, BindableObjectDefinePropertyCall, @@ -133,6 +132,8 @@ import { DeferredTypeReference, DeleteExpression, Diagnostic, + DiagnosticAndArguments, + DiagnosticArguments, DiagnosticCategory, DiagnosticMessage, DiagnosticMessageChain, @@ -896,6 +897,7 @@ import { PropertySignature, PseudoBigInt, pseudoBigIntToString, + PunctuationSyntaxKind, pushIfUnique, QualifiedName, QuestionToken, @@ -2298,10 +2300,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return emitResolver; } - function lookupOrIssueError(location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { + function lookupOrIssueError(location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { const diagnostic = location - ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) - : createCompilerDiagnostic(message, arg0, arg1, arg2, arg3); + ? createDiagnosticForNode(location, message, ...args) + : createCompilerDiagnostic(message, ...args); const existing = diagnostics.lookup(diagnostic); if (existing) { return existing; @@ -2312,20 +2314,20 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function errorSkippedOn(key: keyof CompilerOptions, location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { - const diagnostic = error(location, message, arg0, arg1, arg2, arg3); + function errorSkippedOn(key: keyof CompilerOptions, location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { + const diagnostic = error(location, message, ...args); diagnostic.skippedOn = key; return diagnostic; } - function createError(location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { + function createError(location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { return location - ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) - : createCompilerDiagnostic(message, arg0, arg1, arg2, arg3); + ? createDiagnosticForNode(location, message, ...args) + : createCompilerDiagnostic(message, ...args); } - function error(location: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic { - const diagnostic = createError(location, message, arg0, arg1, arg2, arg3); + function error(location: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { + const diagnostic = createError(location, message, ...args); diagnostics.add(diagnostic); return diagnostic; } @@ -2338,7 +2340,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { suggestionDiagnostics.add({ ...diagnostic, category: DiagnosticCategory.Suggestion }); } } - function errorOrSuggestion(isError: boolean, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { + function errorOrSuggestion(isError: boolean, location: Node, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): void { // Pseudo-synthesized input node if (location.pos < 0 || location.end < 0) { if (!isError) { @@ -2346,18 +2348,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Issue errors globally const file = getSourceFileOfNode(location); - addErrorOrSuggestion(isError, "message" in message ? createFileDiagnostic(file, 0, 0, message, arg0, arg1, arg2, arg3) : createDiagnosticForFileFromMessageChain(file, message)); // eslint-disable-line local/no-in-operator + addErrorOrSuggestion(isError, "message" in message ? createFileDiagnostic(file, 0, 0, message, ...args) : createDiagnosticForFileFromMessageChain(file, message)); // eslint-disable-line local/no-in-operator return; } - addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, arg0, arg1, arg2, arg3) : createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(location), location, message)); // eslint-disable-line local/no-in-operator + addErrorOrSuggestion(isError, "message" in message ? createDiagnosticForNode(location, message, ...args) : createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(location), location, message)); // eslint-disable-line local/no-in-operator } function errorAndMaybeSuggestAwait( location: Node, maybeMissingAwait: boolean, message: DiagnosticMessage, - arg0?: string | number | undefined, arg1?: string | number | undefined, arg2?: string | number | undefined, arg3?: string | number | undefined): Diagnostic { - const diagnostic = error(location, message, arg0, arg1, arg2, arg3); + ...args: DiagnosticArguments): Diagnostic { + const diagnostic = error(location, message, ...args); if (maybeMissingAwait) { const related = createDiagnosticForNode(location, Diagnostics.Did_you_forget_to_use_await); addRelatedInfo(diagnostic, related); @@ -9812,7 +9814,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return result || types; } - function visibilityToString(flags: ModifierFlags): string | undefined { + function visibilityToString(flags: ModifierFlags): string { if (flags === ModifierFlags.Private) { return "private"; } @@ -19755,7 +19757,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*errorReporter*/ undefined, /*errorReporter*/ undefined, compareTypesAssignable, /*reportUnreliableMarkers*/ undefined) !== Ternary.False; } - type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void; + type ErrorReporter = (message: DiagnosticMessage, ...args: DiagnosticArguments) => void; /** * Returns true if `s` is `(...args: A) => R` where `A` is `any`, `any[]`, `never`, or `never[]`, and `R` is `any` or `unknown`. @@ -20190,7 +20192,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let overflow = false; let overrideNextErrorInfo = 0; // How many `reportRelationError` calls should be skipped in the elaboration pyramid let lastSkippedInfo: [Type, Type] | undefined; - let incompatibleStack: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] | undefined; + let incompatibleStack: DiagnosticAndArguments[] | undefined; Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking"); @@ -20263,10 +20265,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { }; } - function reportIncompatibleError(message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number) { + function reportIncompatibleError(message: DiagnosticMessage, ...args: DiagnosticArguments) { overrideNextErrorInfo++; // Suppress the next relation error lastSkippedInfo = undefined; // Reset skipped info cache - (incompatibleStack ||= []).push([message, arg0, arg1, arg2, arg3]); + (incompatibleStack ||= []).push([message, ...args]); } function reportIncompatibleStack() { @@ -20285,7 +20287,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // The first error will be the innermost, while the last will be the outermost - so by popping off the end, // we can build from left to right let path = ""; - const secondaryRootErrors: [DiagnosticMessage, (string | number)?, (string | number)?, (string | number)?, (string | number)?][] = []; + const secondaryRootErrors: DiagnosticAndArguments[] = []; while (stack.length) { const [msg, ...args] = stack.pop()!; switch (msg.code) { @@ -20377,11 +20379,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function reportError(message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { + function reportError(message: DiagnosticMessage, ...args: DiagnosticArguments): void { Debug.assert(!!errorNode); if (incompatibleStack) reportIncompatibleStack(); if (message.elidedInCompatabilityPyramid) return; - errorInfo = chainDiagnosticMessages(errorInfo, message, arg0, arg1, arg2, arg3); + errorInfo = chainDiagnosticMessages(errorInfo, message, ...args); } function associateRelatedInfo(info: DiagnosticRelatedInformation) { @@ -32749,17 +32751,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return { start, length, sourceFile }; } - function getDiagnosticForCallNode(node: CallLikeExpression, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { + function getDiagnosticForCallNode(node: CallLikeExpression, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): DiagnosticWithLocation { if (isCallExpression(node)) { const { sourceFile, start, length } = getDiagnosticSpanForCallNode(node); if ("message" in message) { // eslint-disable-line local/no-in-operator - return createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2, arg3); + return createFileDiagnostic(sourceFile, start, length, message, ...args); } return createDiagnosticForFileFromMessageChain(sourceFile, message); } else { if ("message" in message) { // eslint-disable-line local/no-in-operator - return createDiagnosticForNode(node, message, arg0, arg1, arg2, arg3); + return createDiagnosticForNode(node, message, ...args); } return createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(node), node, message); } @@ -32843,13 +32845,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const parameter = closestSignature?.declaration?.parameters[closestSignature.thisParameter ? args.length + 1 : args.length]; if (parameter) { - const parameterError = createDiagnosticForNode( - parameter, - isBindingPattern(parameter.name) ? Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided - : isRestParameter(parameter) ? Diagnostics.Arguments_for_the_rest_parameter_0_were_not_provided - : Diagnostics.An_argument_for_0_was_not_provided, - !parameter.name ? args.length : !isBindingPattern(parameter.name) ? idText(getFirstIdentifier(parameter.name)) : undefined - ); + const messageAndArgs: DiagnosticAndArguments = + isBindingPattern(parameter.name) ? [Diagnostics.An_argument_matching_this_binding_pattern_was_not_provided] + : isRestParameter(parameter) ? [Diagnostics.Arguments_for_the_rest_parameter_0_were_not_provided, idText(getFirstIdentifier(parameter.name))] + : [Diagnostics.An_argument_for_0_was_not_provided, !parameter.name ? args.length : idText(getFirstIdentifier(parameter.name))]; + const parameterError = createDiagnosticForNode(parameter, ...messageAndArgs); return addRelatedInfo(diagnostic, parameterError); } return diagnostic; @@ -36602,7 +36602,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Note that this and `checkBinaryExpression` above should behave mostly the same, except this elides some // expression-wide checks and does not use a work stack to fold nested binary expressions into the same callstack frame - function checkBinaryLikeExpression(left: Expression, operatorToken: Node, right: Expression, checkMode?: CheckMode, errorNode?: Node): Type { + function checkBinaryLikeExpression(left: Expression, operatorToken: BinaryOperatorToken, right: Expression, checkMode?: CheckMode, errorNode?: Node): Type { const operator = operatorToken.kind; if (operator === SyntaxKind.EqualsToken && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression)) { return checkDestructuringAssignment(left, checkExpression(right, checkMode), checkMode, right.kind === SyntaxKind.ThisKeyword); @@ -36621,7 +36621,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkBinaryLikeExpressionWorker( left: Expression, - operatorToken: Node, + operatorToken: BinaryOperatorToken, right: Expression, leftType: Type, rightType: Type, @@ -36658,7 +36658,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { leftType = checkNonNullType(leftType, left); rightType = checkNonNullType(rightType, right); - let suggestedOperator: SyntaxKind | undefined; + let suggestedOperator: PunctuationSyntaxKind | undefined; // if a user tries to apply a bitwise operator to 2 boolean operands // try and return them a helpful suggestion if ((leftType.flags & TypeFlags.BooleanLike) && @@ -36887,7 +36887,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // Return true if there was no error, false if there was an error. - function checkForDisallowedESSymbolOperand(operator: SyntaxKind): boolean { + function checkForDisallowedESSymbolOperand(operator: PunctuationSyntaxKind): boolean { const offendingSymbolOperand = maybeTypeOfKindConsideringBaseConstraint(leftType, TypeFlags.ESSymbolLike) ? left : maybeTypeOfKindConsideringBaseConstraint(rightType, TypeFlags.ESSymbolLike) ? right : @@ -36901,7 +36901,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function getSuggestedBooleanOperator(operator: SyntaxKind): SyntaxKind | undefined { + function getSuggestedBooleanOperator(operator: SyntaxKind): PunctuationSyntaxKind | undefined { switch (operator) { case SyntaxKind.BarToken: case SyntaxKind.BarEqualsToken: @@ -36926,7 +36926,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let assigneeType = leftType; // getters can be a subtype of setters, so to check for assignability we use the setter's type instead - if (isCompoundAssignment(operatorToken.kind as BinaryOperator) && left.kind === SyntaxKind.PropertyAccessExpression) { + if (isCompoundAssignment(operatorToken.kind) && left.kind === SyntaxKind.PropertyAccessExpression) { assigneeType = checkPropertyAccessExpression(left as PropertyAccessExpression, /*checkMode*/ undefined, /*writeOnly*/ true); } @@ -39178,9 +39178,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function getAwaitedTypeOfPromise(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { + function getAwaitedTypeOfPromise(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): Type | undefined { const promisedType = getPromisedTypeOfPromise(type, errorNode); - return promisedType && getAwaitedType(promisedType, errorNode, diagnosticMessage, arg0); + return promisedType && getAwaitedType(promisedType, errorNode, diagnosticMessage, ...args); } /** @@ -39277,10 +39277,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * Promise-like type; otherwise, it is the type of the expression. This is used to reflect * The runtime behavior of the `await` keyword. */ - function checkAwaitedType(type: Type, withAlias: boolean, errorNode: Node, diagnosticMessage: DiagnosticMessage, arg0?: string | number): Type { + function checkAwaitedType(type: Type, withAlias: boolean, errorNode: Node, diagnosticMessage: DiagnosticMessage, ...args: DiagnosticArguments): Type { const awaitedType = withAlias ? - getAwaitedType(type, errorNode, diagnosticMessage, arg0) : - getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, arg0); + getAwaitedType(type, errorNode, diagnosticMessage, ...args) : + getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, ...args); return awaitedType || errorType; } @@ -39383,8 +39383,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * This is used to reflect the runtime behavior of the `await` keyword. */ - function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { - const awaitedType = getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, arg0); + function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): Type | undefined { + const awaitedType = getAwaitedTypeNoAlias(type, errorNode, diagnosticMessage, ...args); return awaitedType && createAwaitedTypeIfNeeded(awaitedType); } @@ -39393,7 +39393,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { * * @see {@link getAwaitedType} */ - function getAwaitedTypeNoAlias(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { + function getAwaitedTypeNoAlias(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): Type | undefined { if (isTypeAny(type)) { return type; } @@ -39418,7 +39418,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return undefined; } - const mapper = errorNode ? (constituentType: Type) => getAwaitedTypeNoAlias(constituentType, errorNode, diagnosticMessage, arg0) : getAwaitedTypeNoAlias; + const mapper = errorNode ? (constituentType: Type) => getAwaitedTypeNoAlias(constituentType, errorNode, diagnosticMessage, ...args) : getAwaitedTypeNoAlias; awaitedTypeStack.push(type.id); const mapped = mapType(type, mapper); @@ -39478,7 +39478,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // Keep track of the type we're about to unwrap to avoid bad recursive promise types. // See the comments above for more information. awaitedTypeStack.push(type.id); - const awaitedType = getAwaitedTypeNoAlias(promisedType, errorNode, diagnosticMessage, arg0); + const awaitedType = getAwaitedTypeNoAlias(promisedType, errorNode, diagnosticMessage, ...args); awaitedTypeStack.pop(); if (!awaitedType) { @@ -39510,7 +39510,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (thisTypeForErrorOut.value) { chain = chainDiagnosticMessages(chain, Diagnostics.The_this_context_of_type_0_is_not_assignable_to_method_s_this_of_type_1, typeToString(type), typeToString(thisTypeForErrorOut.value)); } - chain = chainDiagnosticMessages(chain, diagnosticMessage, arg0); + chain = chainDiagnosticMessages(chain, diagnosticMessage, ...args); diagnostics.add(createDiagnosticForNodeFromMessageChain(getSourceFileOfNode(errorNode), errorNode, chain)); } return undefined; @@ -40251,9 +40251,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { : rangeOfTypeParameters(sourceFile, parent.typeParameters!); const only = parent.typeParameters!.length === 1; //TODO: following line is possible reason for bug #41974, unusedTypeParameters_TemplateTag - const message = only ? Diagnostics._0_is_declared_but_its_value_is_never_read : Diagnostics.All_type_parameters_are_unused; - const arg0 = only ? name : undefined; - addDiagnostic(typeParameter, UnusedKind.Parameter, createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, message, arg0)); + const messageAndArg: DiagnosticAndArguments = only + ? [Diagnostics._0_is_declared_but_its_value_is_never_read, name] + : [Diagnostics.All_type_parameters_are_unused]; + addDiagnostic(typeParameter, UnusedKind.Parameter, createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, ...messageAndArg)); } } else { @@ -42292,7 +42293,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { forEachKey(catchClause.locals!, caughtName => { const blockLocal = blockLocals.get(caughtName); if (blockLocal?.valueDeclaration && (blockLocal.flags & SymbolFlags.BlockScopedVariable) !== 0) { - grammarErrorOnNode(blockLocal.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, caughtName); + grammarErrorOnNode(blockLocal.valueDeclaration, Diagnostics.Cannot_redeclare_identifier_0_in_catch_clause, unescapeLeadingUnderscores(caughtName)); } }); } @@ -48256,12 +48257,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { switch (node.keywordToken) { case SyntaxKind.NewKeyword: if (escapedText !== "target") { - return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, node.name.escapedText, tokenToString(node.keywordToken), "target"); + return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, unescapeLeadingUnderscores(node.name.escapedText), tokenToString(node.keywordToken), "target"); } break; case SyntaxKind.ImportKeyword: if (escapedText !== "meta") { - return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, node.name.escapedText, tokenToString(node.keywordToken), "meta"); + return grammarErrorOnNode(node.name, Diagnostics._0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2, unescapeLeadingUnderscores(node.name.escapedText), tokenToString(node.keywordToken), "meta"); } break; } @@ -48271,38 +48272,38 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return sourceFile.parseDiagnostics.length > 0; } - function grammarErrorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + function grammarErrorOnFirstToken(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { const span = getSpanOfTokenAtPosition(sourceFile, node.pos); - diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2)); + diagnostics.add(createFileDiagnostic(sourceFile, span.start, span.length, message, ...args)); return true; } return false; } - function grammarErrorAtPos(nodeForSourceFile: Node, start: number, length: number, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + function grammarErrorAtPos(nodeForSourceFile: Node, start: number, length: number, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { const sourceFile = getSourceFileOfNode(nodeForSourceFile); if (!hasParseDiagnostics(sourceFile)) { - diagnostics.add(createFileDiagnostic(sourceFile, start, length, message, arg0, arg1, arg2)); + diagnostics.add(createFileDiagnostic(sourceFile, start, length, message, ...args)); return true; } return false; } - function grammarErrorOnNodeSkippedOn(key: keyof CompilerOptions, node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + function grammarErrorOnNodeSkippedOn(key: keyof CompilerOptions, node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { - errorSkippedOn(key, node, message, arg0, arg1, arg2); + errorSkippedOn(key, node, message, ...args); return true; } return false; } - function grammarErrorOnNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + function grammarErrorOnNode(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { - diagnostics.add(createDiagnosticForNode(node, message, arg0, arg1, arg2)); + diagnostics.add(createDiagnosticForNode(node, message, ...args)); return true; } return false; @@ -48517,11 +48518,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return false; } - function grammarErrorAfterFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { + function grammarErrorAfterFirstToken(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean { const sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { const span = getSpanOfTokenAtPosition(sourceFile, node.pos); - diagnostics.add(createFileDiagnostic(sourceFile, textSpanEnd(span), /*length*/ 0, message, arg0, arg1, arg2)); + diagnostics.add(createFileDiagnostic(sourceFile, textSpanEnd(span), /*length*/ 0, message, ...args)); return true; } return false; diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 556be8387a9fe..0b3e7897f7e0c 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -22,6 +22,7 @@ import { createGetCanonicalFileName, Debug, Diagnostic, + DiagnosticArguments, DiagnosticMessage, Diagnostics, DidYouMeanOptionsDiagnostics, @@ -1692,7 +1693,7 @@ export function createCompilerDiagnosticForInvalidCustomType(opt: CommandLineOpt return createDiagnosticForInvalidCustomType(opt, createCompilerDiagnostic); } -function createDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType, createDiagnostic: (message: DiagnosticMessage, arg0: string, arg1: string) => Diagnostic): Diagnostic { +function createDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType, createDiagnostic: (message: DiagnosticMessage, ...args: DiagnosticArguments) => Diagnostic): Diagnostic { const namesOfType = arrayFrom(opt.type.keys()); const stringNames = (opt.deprecatedKeys ? namesOfType.filter(k => !opt.deprecatedKeys!.has(k)) : namesOfType).map(key => `'${key}'`).join(", "); return createDiagnostic(Diagnostics.Argument_for_0_option_must_be_Colon_1, `--${opt.name}`, stringNames); @@ -2994,9 +2995,9 @@ function parseJsonConfigFileContentWorker( return "no-prop"; } - function createCompilerDiagnosticOnlyIfJson(message: DiagnosticMessage, arg0?: string, arg1?: string) { + function createCompilerDiagnosticOnlyIfJson(message: DiagnosticMessage, ...args: DiagnosticArguments) { if (!sourceFile) { - errors.push(createCompilerDiagnostic(message, arg0, arg1)); + errors.push(createCompilerDiagnostic(message, ...args)); } } } @@ -3445,10 +3446,10 @@ function convertOptionsFromJson(optionsNameMap: Map, return defaultOptions; } -function createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile: TsConfigSourceFile | undefined, node: Node | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number) { +function createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile: TsConfigSourceFile | undefined, node: Node | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) { return sourceFile && node ? - createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2, arg3) : - createCompilerDiagnostic(message, arg0, arg1, arg2, arg3); + createDiagnosticForNodeInSourceFile(sourceFile, node, message, ...args) : + createCompilerDiagnostic(message, ...args); } /** @internal */ @@ -3519,8 +3520,8 @@ function convertJsonOptionOfCustomType( return validateJsonOptionValue(opt, val, errors, valueExpression, sourceFile); } else { - errors.push(createDiagnosticForInvalidCustomType(opt, (message, arg0, arg1) => - createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, valueExpression, message, arg0, arg1))); + errors.push(createDiagnosticForInvalidCustomType(opt, (message, ...args) => + createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, valueExpression, message, ...args))); } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index dedb099abfa65..31252f5f819b1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -5242,7 +5242,7 @@ "category": "Error", "code": 6258 }, - "Found 1 error in {1}": { + "Found 1 error in {0}": { "category": "Message", "code": 6259 }, diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e21c2fa1ff9f2..d5b02a13d0b2b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -63,6 +63,7 @@ import { DefaultClause, DeleteExpression, Diagnostic, + DiagnosticArguments, DiagnosticMessage, Diagnostics, DiagnosticWithDetachedLocation, @@ -149,6 +150,7 @@ import { isJsxOpeningElement, isJsxOpeningFragment, isKeyword, + isKeywordOrPunctuation, isLeftHandSideExpression, isLiteralKind, isMetaProperty, @@ -306,6 +308,8 @@ import { PropertyDeclaration, PropertyName, PropertySignature, + PunctuationOrKeywordSyntaxKind, + PunctuationSyntaxKind, QualifiedName, QuestionDotToken, QuestionToken, @@ -380,6 +384,7 @@ import { TypeQueryNode, TypeReferenceNode, UnaryExpression, + unescapeLeadingUnderscores, UnionOrIntersectionTypeNode, UnionTypeNode, UpdateExpression, @@ -2096,16 +2101,16 @@ namespace Parser { return inContext(NodeFlags.AwaitContext); } - function parseErrorAtCurrentToken(message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { - return parseErrorAt(scanner.getTokenStart(), scanner.getTokenEnd(), message, arg0); + function parseErrorAtCurrentToken(message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation | undefined { + return parseErrorAt(scanner.getTokenStart(), scanner.getTokenEnd(), message, ...args); } - function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { + function parseErrorAtPosition(start: number, length: number, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation | undefined { // Don't report another error if it would just be at the same position as the last error. const lastError = lastOrUndefined(parseDiagnostics); let result: DiagnosticWithDetachedLocation | undefined; if (!lastError || start !== lastError.start) { - result = createDetachedDiagnostic(fileName, start, length, message, arg0); + result = createDetachedDiagnostic(fileName, start, length, message, ...args); parseDiagnostics.push(result); } @@ -2115,12 +2120,12 @@ namespace Parser { return result; } - function parseErrorAt(start: number, end: number, message: DiagnosticMessage, arg0?: any): DiagnosticWithDetachedLocation | undefined { - return parseErrorAtPosition(start, end - start, message, arg0); + function parseErrorAt(start: number, end: number, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation | undefined { + return parseErrorAtPosition(start, end - start, message, ...args); } - function parseErrorAtRange(range: TextRange, message: DiagnosticMessage, arg0?: any): void { - parseErrorAt(range.pos, range.end, message, arg0); + function parseErrorAtRange(range: TextRange, message: DiagnosticMessage, ...args: DiagnosticArguments): void { + parseErrorAt(range.pos, range.end, message, ...args); } function scanError(message: DiagnosticMessage, length: number): void { @@ -2289,7 +2294,7 @@ namespace Parser { return token() > SyntaxKind.LastReservedWord; } - function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean { + function parseExpected(kind: PunctuationOrKeywordSyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldAdvance = true): boolean { if (token() === kind) { if (shouldAdvance) { nextToken(); @@ -2444,11 +2449,12 @@ namespace Parser { nextTokenJSDoc(); return true; } + Debug.assert(isKeywordOrPunctuation(kind)); parseErrorAtCurrentToken(Diagnostics._0_expected, tokenToString(kind)); return false; } - function parseExpectedMatchingBrackets(openKind: SyntaxKind, closeKind: SyntaxKind, openParsed: boolean, openPosition: number) { + function parseExpectedMatchingBrackets(openKind: PunctuationSyntaxKind, closeKind: PunctuationSyntaxKind, openParsed: boolean, openPosition: number) { if (token() === closeKind) { nextToken(); return; @@ -2489,16 +2495,18 @@ namespace Parser { return undefined; } - function parseExpectedToken(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token; - function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: any): Node { + function parseExpectedToken(t: TKind, diagnosticMessage?: DiagnosticMessage, arg0?: string): Token; + function parseExpectedToken(t: SyntaxKind, diagnosticMessage?: DiagnosticMessage, arg0?: string): Node { return parseOptionalToken(t) || - createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t)); + createMissingNode(t, /*reportAtCurrentPosition*/ false, diagnosticMessage || Diagnostics._0_expected, arg0 || tokenToString(t)!); } function parseExpectedTokenJSDoc(t: TKind): Token; function parseExpectedTokenJSDoc(t: JSDocSyntaxKind): Node { - return parseOptionalTokenJSDoc(t) || - createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t)); + const optional = parseOptionalTokenJSDoc(t); + if (optional) return optional; + Debug.assert(isKeywordOrPunctuation(t)); + return createMissingNode(t, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(t)); } function parseTokenNode(): T { @@ -2565,14 +2573,14 @@ namespace Parser { return node; } - function createMissingNode(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, arg0?: any): T; - function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T; - function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage?: DiagnosticMessage, arg0?: any): T { + function createMissingNode(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): T; + function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, ...args: DiagnosticArguments): T; + function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage?: DiagnosticMessage, ...args: DiagnosticArguments): T { if (reportAtCurrentPosition) { - parseErrorAtPosition(scanner.getTokenFullStart(), 0, diagnosticMessage!, arg0); + parseErrorAtPosition(scanner.getTokenFullStart(), 0, diagnosticMessage!, ...args); } else if (diagnosticMessage) { - parseErrorAtCurrentToken(diagnosticMessage, arg0); + parseErrorAtCurrentToken(diagnosticMessage, ...args); } const pos = getNodePos(); @@ -3356,7 +3364,7 @@ namespace Parser { case ParsingContext.HeritageClauseElement: return parseErrorAtCurrentToken(Diagnostics.Expression_expected); case ParsingContext.VariableDeclarations: return isKeyword(token()) - ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, tokenToString(token())) + ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_variable_declaration_name, tokenToString(token())!) : parseErrorAtCurrentToken(Diagnostics.Variable_declaration_expected); case ParsingContext.ObjectBindingElements: return parseErrorAtCurrentToken(Diagnostics.Property_destructuring_pattern_expected); case ParsingContext.ArrayBindingElements: return parseErrorAtCurrentToken(Diagnostics.Array_element_destructuring_pattern_expected); @@ -3366,7 +3374,7 @@ namespace Parser { case ParsingContext.JSDocParameters: return parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); case ParsingContext.Parameters: return isKeyword(token()) - ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_parameter_name, tokenToString(token())) + ? parseErrorAtCurrentToken(Diagnostics._0_is_not_allowed_as_a_parameter_name, tokenToString(token())!) : parseErrorAtCurrentToken(Diagnostics.Parameter_declaration_expected); case ParsingContext.TypeParameters: return parseErrorAtCurrentToken(Diagnostics.Type_parameter_declaration_expected); case ParsingContext.TypeArguments: return parseErrorAtCurrentToken(Diagnostics.Type_argument_expected); @@ -3471,7 +3479,7 @@ namespace Parser { return !!(arr as MissingList).isMissingList; } - function parseBracketedList(kind: ParsingContext, parseElement: () => T, open: SyntaxKind, close: SyntaxKind): NodeArray { + function parseBracketedList(kind: ParsingContext, parseElement: () => T, open: PunctuationSyntaxKind, close: PunctuationSyntaxKind): NodeArray { if (parseExpected(open)) { const result = parseDelimitedList(kind, parseElement); parseExpected(close); @@ -5653,6 +5661,7 @@ namespace Parser { parseErrorAt(pos, end, Diagnostics.A_type_assertion_expression_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses); } else { + Debug.assert(isKeywordOrPunctuation(unaryOperator)); parseErrorAt(pos, end, Diagnostics.An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_expression_Consider_enclosing_the_expression_in_parentheses, tokenToString(unaryOperator)); } } @@ -9119,7 +9128,7 @@ namespace Parser { function parseReturnTag(start: number, tagName: Identifier, indent: number, indentText: string): JSDocReturnTag { if (some(tags, isJSDocReturnTag)) { - parseErrorAt(tagName.pos, scanner.getTokenStart(), Diagnostics._0_tag_already_specified, tagName.escapedText); + parseErrorAt(tagName.pos, scanner.getTokenStart(), Diagnostics._0_tag_already_specified, unescapeLeadingUnderscores(tagName.escapedText)); } const typeExpression = tryParseTypeExpression(); @@ -9128,7 +9137,7 @@ namespace Parser { function parseTypeTag(start: number, tagName: Identifier, indent?: number, indentText?: string): JSDocTypeTag { if (some(tags, isJSDocTypeTag)) { - parseErrorAt(tagName.pos, scanner.getTokenStart(), Diagnostics._0_tag_already_specified, tagName.escapedText); + parseErrorAt(tagName.pos, scanner.getTokenStart(), Diagnostics._0_tag_already_specified, unescapeLeadingUnderscores(tagName.escapedText)); } const typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 60d4647f8d384..e0014f7c730ea 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -56,6 +56,7 @@ import { Debug, DeclarationWithTypeParameterChildren, Diagnostic, + DiagnosticArguments, DiagnosticCategory, diagnosticCategoryName, DiagnosticMessage, @@ -3075,15 +3076,15 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } - function createDiagnosticForNodeArray(nodes: NodeArray, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation { + function createDiagnosticForNodeArray(nodes: NodeArray, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { const start = nodes.pos; - return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2); + return createFileDiagnostic(sourceFile, start, nodes.end - start, message, ...args); } // Since these are syntactic diagnostics, parent might not have been set // this means the sourceFile cannot be infered from the node - function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number): DiagnosticWithLocation { - return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2); + function createDiagnosticForNode(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { + return createDiagnosticForNodeInSourceFile(sourceFile, node, message, ...args); } }); } @@ -3785,7 +3786,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg existingFile, reason, Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict, - [typeReferenceDirective, resolvedTypeReferenceDirective.resolvedFileName, previousResolution.resolvedFileName] + [typeReferenceDirective, resolvedTypeReferenceDirective.resolvedFileName!, previousResolution.resolvedFileName!] ); } } @@ -3840,11 +3841,12 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts"); const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity); const diagnostic = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0; + const args = suggestion ? [libName, suggestion] : [libName]; (fileProcessingDiagnostics ||= []).push({ kind: FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic, reason: { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, }, diagnostic, - args: [libName, suggestion] + args, }); } }); @@ -4343,7 +4345,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg function checkDeprecations( deprecatedIn: string, removedIn: string, - createDiagnostic: (name: string, value: string | undefined, useInstead: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number) => void, + createDiagnostic: (name: string, value: string | undefined, useInstead: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) => void, fn: (createDeprecatedDiagnostic: (name: string, value?: string, useInstead?: string) => void) => void, ) { const deprecatedInVersion = new Version(deprecatedIn); @@ -4377,14 +4379,14 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } function verifyDeprecatedCompilerOptions() { - function createDiagnostic(name: string, value: string | undefined, useInstead: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number) { + function createDiagnostic(name: string, value: string | undefined, useInstead: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) { if (useInstead) { const details = chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Use_0_instead, useInstead); - const chain = chainDiagnosticMessages(details, message, arg0, arg1, arg2, arg3); + const chain = chainDiagnosticMessages(details, message, ...args); createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, chain); } else { - createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, message, arg0, arg1, arg2, arg3); + createDiagnosticForOption(/*onKey*/ !value, name, /*option2*/ undefined, message, ...args); } } @@ -4423,8 +4425,8 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } function verifyDeprecatedProjectReference(ref: ProjectReference, parentFile: JsonSourceFile | undefined, index: number) { - function createDiagnostic(_name: string, _value: string | undefined, _useInstead: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number) { - createDiagnosticForReference(parentFile, index, message, arg0, arg1, arg2, arg3); + function createDiagnostic(_name: string, _value: string | undefined, _useInstead: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments) { + createDiagnosticForReference(parentFile, index, message, ...args); } checkDeprecations("5.0", "5.5", createDiagnostic, createDeprecatedDiagnostic => { @@ -4434,7 +4436,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg }); } - function createDiagnosticExplainingFile(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason | undefined, diagnostic: DiagnosticMessage, args: (string | number | undefined)[] | undefined): Diagnostic { + function createDiagnosticExplainingFile(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason | undefined, diagnostic: DiagnosticMessage, args: DiagnosticArguments | undefined): Diagnostic { let fileIncludeReasons: DiagnosticMessageChain[] | undefined; let relatedInfo: Diagnostic[] | undefined; let locationReason = isReferencedFile(fileProcessingReason) ? fileProcessingReason : undefined; @@ -4464,7 +4466,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } } - function addFilePreprocessingFileExplainingDiagnostic(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason, diagnostic: DiagnosticMessage, args?: (string | number | undefined)[]) { + function addFilePreprocessingFileExplainingDiagnostic(file: SourceFile | undefined, fileProcessingReason: FileIncludeReason, diagnostic: DiagnosticMessage, args?: DiagnosticArguments) { (fileProcessingDiagnostics ||= []).push({ kind: FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic, file: file && file.path, @@ -4474,7 +4476,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg }); } - function addProgramDiagnosticExplainingFile(file: SourceFile, diagnostic: DiagnosticMessage, args?: (string | number | undefined)[]) { + function addProgramDiagnosticExplainingFile(file: SourceFile, diagnostic: DiagnosticMessage, args?: DiagnosticArguments) { programDiagnostics.add(createDiagnosticExplainingFile(file, /*fileProcessingReason*/ undefined, diagnostic, args)); } @@ -4606,7 +4608,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg }); } - function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number) { + function createDiagnosticForOptionPathKeyValue(key: string, valueIndex: number, message: DiagnosticMessage, ...args: DiagnosticArguments) { let needCompilerDiagnostic = true; const pathsSyntax = getOptionPathsSyntax(); for (const pathProp of pathsSyntax) { @@ -4614,7 +4616,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg for (const keyProps of getPropertyAssignment(pathProp.initializer, key)) { const initializer = keyProps.initializer; if (isArrayLiteralExpression(initializer) && initializer.elements.length > valueIndex) { - programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, initializer.elements[valueIndex], message, arg0, arg1, arg2)); + programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, initializer.elements[valueIndex], message, ...args)); needCompilerDiagnostic = false; } } @@ -4622,23 +4624,23 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } if (needCompilerDiagnostic) { - programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2)); + programDiagnostics.add(createCompilerDiagnostic(message, ...args)); } } - function createDiagnosticForOptionPaths(onKey: boolean, key: string, message: DiagnosticMessage, arg0: string | number) { + function createDiagnosticForOptionPaths(onKey: boolean, key: string, message: DiagnosticMessage, ...args: DiagnosticArguments) { let needCompilerDiagnostic = true; const pathsSyntax = getOptionPathsSyntax(); for (const pathProp of pathsSyntax) { if (isObjectLiteralExpression(pathProp.initializer) && createOptionDiagnosticInObjectLiteralSyntax( pathProp.initializer, onKey, key, /*key2*/ undefined, - message, arg0)) { + message, ...args)) { needCompilerDiagnostic = false; } } if (needCompilerDiagnostic) { - programDiagnostics.add(createCompilerDiagnostic(message, arg0)); + programDiagnostics.add(createCompilerDiagnostic(message, ...args)); } } @@ -4662,30 +4664,31 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } function createDiagnosticForOptionName(message: DiagnosticMessage, option1: string, option2?: string, option3?: string) { - createDiagnosticForOption(/*onKey*/ true, option1, option2, message, option1, option2, option3); + // TODO(jakebailey): this code makes assumptions about the format of the diagnostic messages. + createDiagnosticForOption(/*onKey*/ true, option1, option2, message, option1, option2!, option3!); } - function createOptionValueDiagnostic(option1: string, message: DiagnosticMessage, arg0?: string, arg1?: string) { - createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, arg0, arg1); + function createOptionValueDiagnostic(option1: string, message: DiagnosticMessage, ...args: DiagnosticArguments) { + createDiagnosticForOption(/*onKey*/ false, option1, /*option2*/ undefined, message, ...args); } - function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number) { + function createDiagnosticForReference(sourceFile: JsonSourceFile | undefined, index: number, message: DiagnosticMessage, ...args: DiagnosticArguments) { const referencesSyntax = firstDefined(getTsConfigPropArray(sourceFile || options.configFile, "references"), property => isArrayLiteralExpression(property.initializer) ? property.initializer : undefined); if (referencesSyntax && referencesSyntax.elements.length > index) { - programDiagnostics.add(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, arg0, arg1, arg2, arg3)); + programDiagnostics.add(createDiagnosticForNodeInSourceFile(sourceFile || options.configFile!, referencesSyntax.elements[index], message, ...args)); } else { - programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2, arg3)); + programDiagnostics.add(createCompilerDiagnostic(message, ...args)); } } function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessageChain): void; - function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void; - function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): void { + function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): void; + function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): void { const compilerOptionsObjectLiteralSyntax = getCompilerOptionsObjectLiteralSyntax(); const needCompilerDiagnostic = !compilerOptionsObjectLiteralSyntax || - !createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, onKey, option1, option2, message, arg0, arg1, arg2, arg3); + !createOptionDiagnosticInObjectLiteralSyntax(compilerOptionsObjectLiteralSyntax, onKey, option1, option2, message, ...args); if (needCompilerDiagnostic) { // eslint-disable-next-line local/no-in-operator @@ -4693,7 +4696,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg programDiagnostics.add(createCompilerDiagnosticFromMessageChain(message)); } else { - programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1, arg2, arg3)); + programDiagnostics.add(createCompilerDiagnostic(message, ...args)); } } } @@ -4715,9 +4718,9 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, messageChain: DiagnosticMessageChain): boolean; - function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): boolean; - function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): boolean; - function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): boolean { + function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): boolean; + function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): boolean; + function createOptionDiagnosticInObjectLiteralSyntax(objectLiteral: ObjectLiteralExpression, onKey: boolean, key1: string, key2: string | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ...args: DiagnosticArguments): boolean { const props = getPropertyAssignment(objectLiteral, key1, key2); for (const prop of props) { // eslint-disable-next-line local/no-in-operator @@ -4725,7 +4728,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg programDiagnostics.add(createDiagnosticForNodeFromMessageChain(options.configFile!, onKey ? prop.name : prop.initializer, message)); } else { - programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, arg0, arg1, arg2, arg3)); + programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, onKey ? prop.name : prop.initializer, message, ...args)); } } return !!props.length; diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 5045b0d5ce665..8a077dc81f40f 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -20,6 +20,7 @@ import { MapLike, parsePseudoBigInt, positionIsSynthesized, + PunctuationOrKeywordSyntaxKind, ScriptTarget, SourceFileLike, SyntaxKind, @@ -388,6 +389,10 @@ function makeReverseMap(source: Map): string[] { } const tokenStrings = makeReverseMap(textToToken); + +/** @internal */ +export function tokenToString(t: PunctuationOrKeywordSyntaxKind): string; +export function tokenToString(t: SyntaxKind): string | undefined; export function tokenToString(t: SyntaxKind): string | undefined { return tokenStrings[t]; } diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 5c650122d1e85..36f4522906f8a 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -368,14 +368,14 @@ export function transformDeclarations(context: TransformationContext) { context.addDiagnostic(createDiagnosticForNode(symbolAccessibilityResult.errorNode || errorInfo.errorNode, errorInfo.diagnosticMessage, getTextOfNode(errorInfo.typeName), - symbolAccessibilityResult.errorSymbolName, - symbolAccessibilityResult.errorModuleName)); + symbolAccessibilityResult.errorSymbolName!, + symbolAccessibilityResult.errorModuleName!)); } else { context.addDiagnostic(createDiagnosticForNode(symbolAccessibilityResult.errorNode || errorInfo.errorNode, errorInfo.diagnosticMessage, - symbolAccessibilityResult.errorSymbolName, - symbolAccessibilityResult.errorModuleName)); + symbolAccessibilityResult.errorSymbolName!, + symbolAccessibilityResult.errorModuleName!)); } return true; } diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index d20992fa298b2..8b6fcfcdbea2f 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -32,6 +32,7 @@ import { CustomTransformers, Debug, Diagnostic, + DiagnosticArguments, DiagnosticCollection, DiagnosticMessage, DiagnosticReporter, @@ -2468,11 +2469,11 @@ function relName(state: SolutionBuilderState, path: return convertToRelativePath(path, state.compilerHost.getCurrentDirectory(), state.compilerHost.getCanonicalFileName); } -function reportStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: string[]) { +function reportStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: DiagnosticArguments) { state.host.reportSolutionBuilderStatus(createCompilerDiagnostic(message, ...args)); } -function reportWatchStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: (string | number | undefined)[]) { +function reportWatchStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: DiagnosticArguments) { state.hostWithWatch.onWatchStatusChange?.(createCompilerDiagnostic(message, ...args), state.host.getNewLine(), state.baseCompilerOptions); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 8ed61e4446b85..82cdb98a8d6b0 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -579,6 +579,9 @@ export type PunctuationSyntaxKind = | SyntaxKind.CaretEqualsToken ; +/** @internal */ +export type PunctuationOrKeywordSyntaxKind = PunctuationSyntaxKind | KeywordSyntaxKind; + export type KeywordSyntaxKind = | SyntaxKind.AbstractKeyword | SyntaxKind.AccessorKeyword @@ -4665,7 +4668,7 @@ export interface FilePreprocessingReferencedDiagnostic { kind: FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic; reason: ReferencedFile; diagnostic: DiagnosticMessage; - args?: (string | number | undefined)[]; + args?: DiagnosticArguments; } /** @internal */ @@ -4674,7 +4677,7 @@ export interface FilePreprocessingFileExplainingDiagnostic { file?: Path; fileProcessingReason: FileIncludeReason; diagnostic: DiagnosticMessage; - args?: (string | number | undefined)[]; + args?: DiagnosticArguments; } /** @internal */ @@ -6918,6 +6921,12 @@ export interface Diagnostic extends DiagnosticRelatedInformation { /** @internal */ skippedOn?: keyof CompilerOptions; } +/** @internal */ +export type DiagnosticArguments = (string | number)[]; + +/** @internal */ +export type DiagnosticAndArguments = [message: DiagnosticMessage, ...args: DiagnosticArguments]; + export interface DiagnosticRelatedInformation { category: DiagnosticCategory; code: number; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 159aedabbf228..d1f5a69aea6fa 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -90,6 +90,7 @@ import { DefaultClause, DestructuringAssignment, Diagnostic, + DiagnosticArguments, DiagnosticCollection, DiagnosticMessage, DiagnosticMessageChain, @@ -440,6 +441,8 @@ import { PropertyNameLiteral, PropertySignature, PseudoBigInt, + PunctuationOrKeywordSyntaxKind, + PunctuationSyntaxKind, QualifiedName, QuestionQuestionEqualsToken, ReadonlyCollection, @@ -2058,21 +2061,21 @@ export function entityNameToString(name: EntityNameOrEntityNameExpression | JSDo } /** @internal */ -export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { +export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { const sourceFile = getSourceFileOfNode(node); - return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2, arg3); + return createDiagnosticForNodeInSourceFile(sourceFile, node, message, ...args); } /** @internal */ -export function createDiagnosticForNodeArray(sourceFile: SourceFile, nodes: NodeArray, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { +export function createDiagnosticForNodeArray(sourceFile: SourceFile, nodes: NodeArray, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { const start = skipTrivia(sourceFile.text, nodes.pos); - return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2, arg3); + return createFileDiagnostic(sourceFile, start, nodes.end - start, message, ...args); } /** @internal */ -export function createDiagnosticForNodeInSourceFile(sourceFile: SourceFile, node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation { +export function createDiagnosticForNodeInSourceFile(sourceFile: SourceFile, node: Node, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation { const span = getErrorSpanForNode(sourceFile, node); - return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2, arg3); + return createFileDiagnostic(sourceFile, span.start, span.length, message, ...args); } /** @internal */ @@ -4771,6 +4774,16 @@ export function isKeyword(token: SyntaxKind): token is KeywordSyntaxKind { return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword; } +/** @internal */ +export function isPunctuation(token: SyntaxKind): token is PunctuationSyntaxKind { + return SyntaxKind.FirstPunctuation <= token && token <= SyntaxKind.LastPunctuation; +} + +/** @internal */ +export function isKeywordOrPunctuation(token: SyntaxKind): token is PunctuationOrKeywordSyntaxKind { + return isKeyword(token) || isPunctuation(token); +} + /** @internal */ export function isContextualKeyword(token: SyntaxKind): boolean { return SyntaxKind.FirstContextualKeyword <= token && token <= SyntaxKind.LastContextualKeyword; @@ -7995,7 +8008,7 @@ export function getLocaleSpecificMessage(message: DiagnosticMessage) { } /** @internal */ -export function createDetachedDiagnostic(fileName: string, start: number, length: number, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticWithDetachedLocation; +export function createDetachedDiagnostic(fileName: string, start: number, length: number, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithDetachedLocation; /** @internal */ export function createDetachedDiagnostic(fileName: string, start: number, length: number, message: DiagnosticMessage): DiagnosticWithDetachedLocation { assertDiagnosticLocation(/*file*/ undefined, start, length); @@ -8066,7 +8079,7 @@ export function attachFileToDiagnostics(diagnostics: DiagnosticWithDetachedLocat } /** @internal */ -export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticWithLocation; +export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticWithLocation; /** @internal */ export function createFileDiagnostic(file: SourceFile, start: number, length: number, message: DiagnosticMessage): DiagnosticWithLocation { assertDiagnosticLocation(file, start, length); @@ -8091,7 +8104,7 @@ export function createFileDiagnostic(file: SourceFile, start: number, length: nu } /** @internal */ -export function formatMessage(_dummy: any, message: DiagnosticMessage, ...args: (string | number | undefined)[]): string; +export function formatMessage(_dummy: any, message: DiagnosticMessage, ...args: DiagnosticArguments): string; /** @internal */ export function formatMessage(_dummy: any, message: DiagnosticMessage): string { let text = getLocaleSpecificMessage(message); @@ -8104,7 +8117,7 @@ export function formatMessage(_dummy: any, message: DiagnosticMessage): string { } /** @internal */ -export function createCompilerDiagnostic(message: DiagnosticMessage, ...args: (string | number | undefined)[]): Diagnostic; +export function createCompilerDiagnostic(message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic; /** @internal */ export function createCompilerDiagnostic(message: DiagnosticMessage): Diagnostic { let text = getLocaleSpecificMessage(message); @@ -8141,7 +8154,7 @@ export function createCompilerDiagnosticFromMessageChain(chain: DiagnosticMessag } /** @internal */ -export function chainDiagnosticMessages(details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, message: DiagnosticMessage, ...args: (string | number | undefined)[]): DiagnosticMessageChain; +export function chainDiagnosticMessages(details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, message: DiagnosticMessage, ...args: DiagnosticArguments): DiagnosticMessageChain; /** @internal */ export function chainDiagnosticMessages(details: DiagnosticMessageChain | DiagnosticMessageChain[] | undefined, message: DiagnosticMessage): DiagnosticMessageChain { let text = getLocaleSpecificMessage(message); diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index 8c4d885d6ce4b..916625460c259 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -22,6 +22,7 @@ import { CustomTransformers, Debug, Diagnostic, + DiagnosticAndArguments, DiagnosticCategory, DiagnosticMessage, DiagnosticMessageChain, @@ -283,22 +284,18 @@ export function getErrorSummaryText( const firstFileReference = nonNilFiles[0] && prettyPathForFileError(nonNilFiles[0], host.getCurrentDirectory()); - const d = errorCount === 1 ? - createCompilerDiagnostic( - filesInError[0] !== undefined ? - Diagnostics.Found_1_error_in_1 : - Diagnostics.Found_1_error, - errorCount, - firstFileReference) : - createCompilerDiagnostic( - distinctFileNamesWithLines.length === 0 ? - Diagnostics.Found_0_errors : - distinctFileNamesWithLines.length === 1 ? - Diagnostics.Found_0_errors_in_the_same_file_starting_at_Colon_1 : - Diagnostics.Found_0_errors_in_1_files, - errorCount, - distinctFileNamesWithLines.length === 1 ? firstFileReference : distinctFileNamesWithLines.length); + let messageAndArgs: DiagnosticAndArguments; + if (errorCount === 1) { + messageAndArgs = filesInError[0] !== undefined ? [Diagnostics.Found_1_error_in_0, firstFileReference!] : [Diagnostics.Found_1_error]; + } + else { + messageAndArgs = + distinctFileNamesWithLines.length === 0 ? [Diagnostics.Found_0_errors, errorCount] : + distinctFileNamesWithLines.length === 1 ? [Diagnostics.Found_0_errors_in_the_same_file_starting_at_Colon_1, errorCount, firstFileReference!] : + [Diagnostics.Found_0_errors_in_1_files, errorCount, distinctFileNamesWithLines.length]; + } + const d = createCompilerDiagnostic(...messageAndArgs); const suffix = distinctFileNamesWithLines.length > 1 ? createTabularErrorsDisplay(nonNilFiles, host) : ""; return `${newLine}${flattenDiagnosticMessageText(d.messageText, newLine)}${newLine}${newLine}${suffix}`; } @@ -489,7 +486,7 @@ export function fileIncludeReasonToDiagnostics(program: Program, reason: FileInc message, referenceText, toFileName(referenceLocation.file, fileNameConvertor), - referenceLocation.packageId && packageIdToString(referenceLocation.packageId) + (referenceLocation.packageId && packageIdToString(referenceLocation.packageId))! ); } switch (reason.kind) { @@ -527,29 +524,23 @@ export function fileIncludeReasonToDiagnostics(program: Program, reason: FileInc toFileName(referencedResolvedRef.sourceFile.fileName, fileNameConvertor), options.outFile ? "--outFile" : "--out", ); - case FileIncludeKind.AutomaticTypeDirectiveFile: - return chainDiagnosticMessages( - /*details*/ undefined, - options.types ? - reason.packageId ? - Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions_with_packageId_1 : - Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions : - reason.packageId ? - Diagnostics.Entry_point_for_implicit_type_library_0_with_packageId_1 : - Diagnostics.Entry_point_for_implicit_type_library_0, - reason.typeReference, - reason.packageId && packageIdToString(reason.packageId), - ); - case FileIncludeKind.LibFile: + case FileIncludeKind.AutomaticTypeDirectiveFile: { + const messageAndArgs: DiagnosticAndArguments = options.types ? + reason.packageId ? + [Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions_with_packageId_1, reason.typeReference, packageIdToString(reason.packageId)] : + [Diagnostics.Entry_point_of_type_library_0_specified_in_compilerOptions, reason.typeReference] : + reason.packageId ? + [Diagnostics.Entry_point_for_implicit_type_library_0_with_packageId_1, reason.typeReference, packageIdToString(reason.packageId)] : + [Diagnostics.Entry_point_for_implicit_type_library_0, reason.typeReference]; + + return chainDiagnosticMessages(/*details*/ undefined, ...messageAndArgs); + } + case FileIncludeKind.LibFile: { if (reason.index !== undefined) return chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Library_0_specified_in_compilerOptions, options.lib![reason.index]); const target = forEachEntry(targetOptionDeclaration.type, (value, key) => value === getEmitScriptTarget(options) ? key : undefined); - return chainDiagnosticMessages( - /*details*/ undefined, - target ? - Diagnostics.Default_library_for_target_0 : - Diagnostics.Default_library, - target, - ); + const messageAndArgs: DiagnosticAndArguments = target ? [Diagnostics.Default_library_for_target_0, target] : [Diagnostics.Default_library]; + return chainDiagnosticMessages(/*details*/ undefined, ...messageAndArgs); + } default: Debug.assertNever(reason); } diff --git a/src/services/codeFixProvider.ts b/src/services/codeFixProvider.ts index cf1594d7785cf..67dbdbc9a9280 100644 --- a/src/services/codeFixProvider.ts +++ b/src/services/codeFixProvider.ts @@ -13,7 +13,7 @@ import { createMultiMap, Debug, Diagnostic, - DiagnosticAndArguments, + DiagnosticOrDiagnosticAndArguments, diagnosticToString, DiagnosticWithLocation, FileTextChanges, @@ -28,17 +28,17 @@ const errorCodeToFixes = createMultiMap(); const fixIdToRegistration = new Map(); /** @internal */ -export function createCodeFixActionWithoutFixAll(fixName: string, changes: FileTextChanges[], description: DiagnosticAndArguments) { +export function createCodeFixActionWithoutFixAll(fixName: string, changes: FileTextChanges[], description: DiagnosticOrDiagnosticAndArguments) { return createCodeFixActionWorker(fixName, diagnosticToString(description), changes, /*fixId*/ undefined, /*fixAllDescription*/ undefined); } /** @internal */ -export function createCodeFixAction(fixName: string, changes: FileTextChanges[], description: DiagnosticAndArguments, fixId: {}, fixAllDescription: DiagnosticAndArguments, command?: CodeActionCommand): CodeFixAction { +export function createCodeFixAction(fixName: string, changes: FileTextChanges[], description: DiagnosticOrDiagnosticAndArguments, fixId: {}, fixAllDescription: DiagnosticOrDiagnosticAndArguments, command?: CodeActionCommand): CodeFixAction { return createCodeFixActionWorker(fixName, diagnosticToString(description), changes, fixId, diagnosticToString(fixAllDescription), command); } /** @internal */ -export function createCodeFixActionMaybeFixAll(fixName: string, changes: FileTextChanges[], description: DiagnosticAndArguments, fixId?: {}, fixAllDescription?: DiagnosticAndArguments, command?: CodeActionCommand) { +export function createCodeFixActionMaybeFixAll(fixName: string, changes: FileTextChanges[], description: DiagnosticOrDiagnosticAndArguments, fixId?: {}, fixAllDescription?: DiagnosticOrDiagnosticAndArguments, command?: CodeActionCommand) { return createCodeFixActionWorker(fixName, diagnosticToString(description), changes, fixId, fixAllDescription && diagnosticToString(fixAllDescription), command); } diff --git a/src/services/codefixes/fixImplicitThis.ts b/src/services/codefixes/fixImplicitThis.ts index c8f02aba81850..86c8adad40bd3 100644 --- a/src/services/codefixes/fixImplicitThis.ts +++ b/src/services/codefixes/fixImplicitThis.ts @@ -1,7 +1,7 @@ import { ANONYMOUS, Debug, - DiagnosticAndArguments, + DiagnosticOrDiagnosticAndArguments, Diagnostics, emptyArray, factory, @@ -30,7 +30,7 @@ registerCodeFix({ errorCodes, getCodeActions: function getCodeActionsToFixImplicitThis(context) { const { sourceFile, program, span } = context; - let diagnostic: DiagnosticAndArguments | undefined; + let diagnostic: DiagnosticOrDiagnosticAndArguments | undefined; const changes = textChanges.ChangeTracker.with(context, t => { diagnostic = doChange(t, sourceFile, span.start, program.getTypeChecker()); }); @@ -42,7 +42,7 @@ registerCodeFix({ }), }); -function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, checker: TypeChecker): DiagnosticAndArguments | undefined { +function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number, checker: TypeChecker): DiagnosticOrDiagnosticAndArguments | undefined { const token = getTokenAtPosition(sourceFile, pos); if (!isThis(token)) return undefined; diff --git a/src/services/codefixes/fixUnusedIdentifier.ts b/src/services/codefixes/fixUnusedIdentifier.ts index 881ce7478604b..4da1d6ce22d9c 100644 --- a/src/services/codefixes/fixUnusedIdentifier.ts +++ b/src/services/codefixes/fixUnusedIdentifier.ts @@ -5,8 +5,8 @@ import { CodeFixAction, CodeFixContext, Debug, - DiagnosticAndArguments, DiagnosticMessage, + DiagnosticOrDiagnosticAndArguments, Diagnostics, factory, FileTextChanges, @@ -220,7 +220,7 @@ function changeInferToUnknown(changes: textChanges.ChangeTracker, sourceFile: So changes.replaceNode(sourceFile, token.parent, factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword)); } -function createDeleteFix(changes: FileTextChanges[], diag: DiagnosticAndArguments): CodeFixAction { +function createDeleteFix(changes: FileTextChanges[], diag: DiagnosticOrDiagnosticAndArguments): CodeFixAction { return createCodeFixAction(fixName, changes, diag, fixIdDelete, Diagnostics.Delete_all_unused_declarations); } diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index fe82e145ed8ca..90a3756f284ea 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -18,7 +18,7 @@ import { createMultiMap, createPackageJsonImportFilter, Debug, - DiagnosticAndArguments, + DiagnosticOrDiagnosticAndArguments, Diagnostics, DiagnosticWithLocation, emptyArray, @@ -1212,13 +1212,13 @@ function getExportEqualsImportKind(importingFile: SourceFile, compilerOptions: C } function codeActionForFix(context: textChanges.TextChangesContext, sourceFile: SourceFile, symbolName: string, fix: ImportFix, includeSymbolNameInDescription: boolean, compilerOptions: CompilerOptions, preferences: UserPreferences): CodeFixAction { - let diag!: DiagnosticAndArguments; + let diag!: DiagnosticOrDiagnosticAndArguments; const changes = textChanges.ChangeTracker.with(context, tracker => { diag = codeActionForFixWorker(tracker, sourceFile, symbolName, fix, includeSymbolNameInDescription, compilerOptions, preferences); }); return createCodeFixAction(importFixName, changes, diag, importFixId, Diagnostics.Add_all_missing_imports); } -function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: SourceFile, symbolName: string, fix: ImportFix, includeSymbolNameInDescription: boolean, compilerOptions: CompilerOptions, preferences: UserPreferences): DiagnosticAndArguments { +function codeActionForFixWorker(changes: textChanges.ChangeTracker, sourceFile: SourceFile, symbolName: string, fix: ImportFix, includeSymbolNameInDescription: boolean, compilerOptions: CompilerOptions, preferences: UserPreferences): DiagnosticOrDiagnosticAndArguments { const quotePreference = getQuotePreference(sourceFile, preferences); switch (fix.kind) { case ImportFixKind.UseNamespace: diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 00446261547a4..d118f336b66d4 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -42,6 +42,8 @@ import { defaultMaximumTruncationLength, DeleteExpression, Diagnostic, + DiagnosticAndArguments, + DiagnosticArguments, DiagnosticMessage, DiagnosticWithLocation, directoryProbablyExists, @@ -2180,11 +2182,6 @@ export function isStringAndEmptyAnonymousObjectIntersection(type: Type) { (areIntersectedTypesAvoidingStringReduction(checker, types[0], types[1]) || areIntersectedTypesAvoidingStringReduction(checker, types[1], types[0])); } -/** @internal */ -export function isPunctuation(kind: SyntaxKind): boolean { - return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation; -} - /** @internal */ export function isInsideTemplateLiteral(node: TemplateLiteralToken, position: number, sourceFile: SourceFile): boolean { return isTemplateLiteralKind(node.kind) @@ -4058,11 +4055,11 @@ export function getNewLineKind(newLineCharacter: string): NewLineKind { } /** @internal */ -export type DiagnosticAndArguments = DiagnosticMessage | [DiagnosticMessage, string] | [DiagnosticMessage, string, string]; +export type DiagnosticOrDiagnosticAndArguments = DiagnosticMessage | DiagnosticAndArguments; /** @internal */ -export function diagnosticToString(diag: DiagnosticAndArguments): string { +export function diagnosticToString(diag: DiagnosticOrDiagnosticAndArguments): string { return isArray(diag) - ? formatStringFromArgs(getLocaleSpecificMessage(diag[0]), diag.slice(1) as readonly string[]) + ? formatStringFromArgs(getLocaleSpecificMessage(diag[0]), diag.slice(1) as DiagnosticArguments) : getLocaleSpecificMessage(diag); }