diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2b3cdcb736d1a..e6545391573d5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1068,6 +1068,69 @@ namespace ts { [".json", ".json"], ]; + const checkExpressionWorkerTable = new Array<(node: any, checkMode: CheckMode | undefined) => Type>(SyntaxKind.Count); + checkExpressionWorkerTable[SyntaxKind.Identifier] = checkIdentifier; + checkExpressionWorkerTable[SyntaxKind.PrivateIdentifier] = checkPrivateIdentifierExpression; + checkExpressionWorkerTable[SyntaxKind.ThisKeyword] = checkThisExpression; + checkExpressionWorkerTable[SyntaxKind.SuperKeyword] = checkSuperExpression; + checkExpressionWorkerTable[SyntaxKind.NullKeyword] = (_node, _checkMode) => nullWideningType; + checkExpressionWorkerTable[SyntaxKind.NoSubstitutionTemplateLiteral] = checkExpressionWorkerTable[SyntaxKind.StringLiteral] = + (node: StringLiteralLike, _checkMode) => getFreshTypeOfLiteralType(getStringLiteralType(node.text)); + checkExpressionWorkerTable[SyntaxKind.NumericLiteral] = (node: NumericLiteral, _checkMode) => { + checkGrammarNumericLiteral(node); + return getFreshTypeOfLiteralType(getNumberLiteralType(+(node).text)); + }; + checkExpressionWorkerTable[SyntaxKind.BigIntLiteral] = (node: BigIntLiteral, _checkMode) => { + checkGrammarBigIntLiteral(node); + return getFreshTypeOfLiteralType(getBigIntLiteralType({ + negative: false, + base10Value: parsePseudoBigInt((node).text) + })); + }; + checkExpressionWorkerTable[SyntaxKind.TrueKeyword] = (_node, _checkMode) => trueType; + checkExpressionWorkerTable[SyntaxKind.FalseKeyword] = (_node, _checkMode) => falseType; + checkExpressionWorkerTable[SyntaxKind.TemplateExpression] = checkTemplateExpression; + checkExpressionWorkerTable[SyntaxKind.RegularExpressionLiteral] = (_node, _checkMode) => globalRegExpType; + checkExpressionWorkerTable[SyntaxKind.ObjectLiteralExpression] = checkObjectLiteral; + checkExpressionWorkerTable[SyntaxKind.PropertyAccessExpression] = checkPropertyAccessExpression; + checkExpressionWorkerTable[SyntaxKind.QualifiedName] = checkQualifiedName; + checkExpressionWorkerTable[SyntaxKind.ElementAccessExpression] = checkIndexedAccess; + checkExpressionWorkerTable[SyntaxKind.CallExpression] = (node: CallExpression, checkMode) => { + if (node.expression.kind === SyntaxKind.ImportKeyword) { + return checkImportCallExpression(node as ImportCall); + }; + return checkCallExpression(node, checkMode); + }; + checkExpressionWorkerTable[SyntaxKind.NewExpression] = checkCallExpression; + checkExpressionWorkerTable[SyntaxKind.TaggedTemplateExpression] = checkTaggedTemplateExpression; + checkExpressionWorkerTable[SyntaxKind.ParenthesizedExpression] = checkParenthesizedExpression; + checkExpressionWorkerTable[SyntaxKind.ClassExpression] = checkClassExpression; + checkExpressionWorkerTable[SyntaxKind.FunctionExpression] = + checkExpressionWorkerTable[SyntaxKind.ArrowFunction] = checkFunctionExpressionOrObjectLiteralMethod; + checkExpressionWorkerTable[SyntaxKind.TypeOfExpression] = checkTypeOfExpression; + checkExpressionWorkerTable[SyntaxKind.TypeAssertionExpression] = + checkExpressionWorkerTable[SyntaxKind.AsExpression] = checkAssertion; + checkExpressionWorkerTable[SyntaxKind.NonNullExpression] = checkNonNullAssertion; + checkExpressionWorkerTable[SyntaxKind.ExpressionWithTypeArguments] = checkExpressionWithTypeArguments; + checkExpressionWorkerTable[SyntaxKind.MetaProperty] = checkMetaProperty; + checkExpressionWorkerTable[SyntaxKind.DeleteExpression] = checkDeleteExpression; + checkExpressionWorkerTable[SyntaxKind.VoidExpression] = checkVoidExpression; + checkExpressionWorkerTable[SyntaxKind.AwaitExpression] = checkAwaitExpression; + checkExpressionWorkerTable[SyntaxKind.PrefixUnaryExpression] = checkPrefixUnaryExpression; + checkExpressionWorkerTable[SyntaxKind.PostfixUnaryExpression] = checkPostfixUnaryExpression; + checkExpressionWorkerTable[SyntaxKind.BinaryExpression] = checkBinaryExpression; + checkExpressionWorkerTable[SyntaxKind.ConditionalExpression] = checkConditionalExpression; + checkExpressionWorkerTable[SyntaxKind.SpreadElement] = checkSpreadExpression; + checkExpressionWorkerTable[SyntaxKind.OmittedExpression] = (_node, _checkMode) => undefinedWideningType; + checkExpressionWorkerTable[SyntaxKind.YieldExpression] = checkYieldExpression; + checkExpressionWorkerTable[SyntaxKind.SyntheticExpression] = checkSyntheticExpression; + checkExpressionWorkerTable[SyntaxKind.JsxExpression] = checkJsxExpression; + checkExpressionWorkerTable[SyntaxKind.JsxElement] = checkJsxElement; + checkExpressionWorkerTable[SyntaxKind.JsxSelfClosingElement] = checkJsxSelfClosingElement; + checkExpressionWorkerTable[SyntaxKind.JsxFragment] = checkJsxFragment; + checkExpressionWorkerTable[SyntaxKind.JsxAttributes] = checkJsxAttributes; + checkExpressionWorkerTable[SyntaxKind.JsxOpeningElement] = (_node, _checkMode) => Debug.fail("Shouldn't ever directly check a JsxOpeningElement"); + initializeTypeChecker(); return checker; @@ -14009,7 +14072,7 @@ namespace ts { // The expression is processed as an identifier expression (section 4.3) // or property access expression(section 4.10), // the widened type(section 3.9) of which becomes the result. - const type = checkExpressionWithTypeArguments(node); + const type = checkExpressionWithTypeArguments(node, /*checkMode*/ undefined); links.resolvedType = getRegularTypeOfLiteralType(getWidenedType(type)); } return links.resolvedType; @@ -24279,7 +24342,7 @@ namespace ts { case SyntaxKind.ThisKeyword: return getExplicitThisType(node); case SyntaxKind.SuperKeyword: - return checkSuperExpression(node); + return checkSuperExpression(node, /*checkMode*/ undefined); case SyntaxKind.PropertyAccessExpression: { const type = getTypeOfDottedName((node as PropertyAccessExpression).expression, diagnostic); if (type) { @@ -25868,7 +25931,7 @@ namespace ts { function checkIdentifier(node: Identifier, checkMode: CheckMode | undefined): Type { if (isThisInTypeQuery(node)) { - return checkThisExpression(node); + return checkThisExpression(node, checkMode); } const symbol = getResolvedSymbol(node); @@ -26226,7 +26289,7 @@ namespace ts { } } - function checkThisExpression(node: Node): Type { + function checkThisExpression(node: Node, _checkMode: CheckMode | undefined): Type { const isNodeInTypeQuery = isInTypeQuery(node); // Stop at the first arrow function so that we can // tell whether 'this' needs to be captured. @@ -26424,7 +26487,7 @@ namespace ts { return !!findAncestor(node, n => isFunctionLikeDeclaration(n) ? "quit" : n.kind === SyntaxKind.Parameter && n.parent === constructorDecl); } - function checkSuperExpression(node: Node): Type { + function checkSuperExpression(node: Node, _checkMode: CheckMode | undefined): Type { const isCallExpression = node.parent.kind === SyntaxKind.CallExpression && (node.parent as CallExpression).expression === node; const immediateContainer = getSuperContainer(node, /*stopOnFunctions*/ true); @@ -27113,7 +27176,7 @@ namespace ts { if (!isObjectLiteralMethod(getThisContainer(thisAccess.expression, /*includeArrowFunctions*/ false))) { return undefined; } - const thisType = checkThisExpression(thisAccess.expression); + const thisType = checkThisExpression(thisAccess.expression, /*checkMode*/ undefined); const nameStr = getElementOrPropertyAccessName(thisAccess); return nameStr !== undefined && getTypeOfPropertyOfContextualType(thisType, nameStr) || undefined; @@ -27795,7 +27858,7 @@ namespace ts { } } - function checkSpreadExpression(node: SpreadElement, checkMode?: CheckMode): Type { + function checkSpreadExpression(node: SpreadElement, checkMode: CheckMode | undefined): Type { if (languageVersion < ScriptTarget.ES2015) { checkExternalEmitHelpers(node, compilerOptions.downlevelIteration ? ExternalEmitHelpers.SpreadIncludes : ExternalEmitHelpers.SpreadArray); } @@ -27804,7 +27867,7 @@ namespace ts { return checkIteratedTypeOrElementType(IterationUse.Spread, arrayOrIterableType, undefinedType, node.expression); } - function checkSyntheticExpression(node: SyntheticExpression): Type { + function checkSyntheticExpression(node: SyntheticExpression, _checkMode: CheckMode | undefined): Type { return node.isSpread ? getIndexedAccessType(node.type, numberType) : node.type; } @@ -28251,7 +28314,7 @@ namespace ts { return getJsxElementTypeAt(node) || anyType; } - function checkJsxFragment(node: JsxFragment): Type { + function checkJsxFragment(node: JsxFragment, _checkMode: CheckMode | undefined): Type { checkJsxOpeningLikeElementOrOpeningFragment(node.openingFragment); // by default, jsx:'react' will use jsxFactory = React.createElement and jsxFragmentFactory = React.Fragment @@ -28842,7 +28905,7 @@ namespace ts { type.flags & TypeFlags.Intersection && every((type as IntersectionType).types, isExcessPropertyCheckTarget)); } - function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) { + function checkJsxExpression(node: JsxExpression, checkMode: CheckMode | undefined) { checkGrammarJsxExpression(node); if (node.expression) { const type = checkExpression(node.expression, checkMode); @@ -29118,7 +29181,7 @@ namespace ts { } function checkQualifiedName(node: QualifiedName, checkMode: CheckMode | undefined) { - const leftType = isPartOfTypeQuery(node) && isThisIdentifier(node.left) ? checkNonNullType(checkThisExpression(node.left), node.left) : checkNonNullExpression(node.left); + const leftType = isPartOfTypeQuery(node) && isThisIdentifier(node.left) ? checkNonNullType(checkThisExpression(node.left, checkMode), node.left) : checkNonNullExpression(node.left); return checkPropertyAccessExpressionOrQualifiedName(node, node.left, leftType, node.right, checkMode); } @@ -29160,7 +29223,7 @@ namespace ts { return false; } - function checkPrivateIdentifierExpression(privId: PrivateIdentifier): Type { + function checkPrivateIdentifierExpression(privId: PrivateIdentifier, _checkMode: CheckMode | undefined): Type { checkGrammarPrivateIdentifierExpression(privId); const symbol = getSymbolForPrivateIdentifierExpression(privId); if (symbol) { @@ -31266,7 +31329,7 @@ namespace ts { function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature { if (node.expression.kind === SyntaxKind.SuperKeyword) { - const superType = checkSuperExpression(node.expression); + const superType = checkSuperExpression(node.expression, checkMode); if (isTypeAny(superType)) { for (const arg of node.arguments) { checkExpression(arg); // Still visit arguments so they get marked for visibility, etc @@ -32223,7 +32286,7 @@ namespace ts { return false; } - function checkTaggedTemplateExpression(node: TaggedTemplateExpression): Type { + function checkTaggedTemplateExpression(node: TaggedTemplateExpression, _checkMode: CheckMode | undefined): Type { if (!checkGrammarTaggedTemplateChain(node)) checkGrammarTypeArguments(node, node.typeArguments); if (languageVersion < ScriptTarget.ES2015) { checkExternalEmitHelpers(node, ExternalEmitHelpers.MakeTemplateObject); @@ -32233,7 +32296,7 @@ namespace ts { return getReturnTypeOfSignature(signature); } - function checkAssertion(node: AssertionExpression) { + function checkAssertion(node: AssertionExpression, _checkMode: CheckMode | undefined) { if (node.kind === SyntaxKind.TypeAssertionExpression) { const file = getSourceFileOfNode(node); if (file && fileExtensionIsOneOf(file.fileName, [Extension.Cts, Extension.Mts])) { @@ -32303,15 +32366,15 @@ namespace ts { return propagateOptionalTypeMarker(getNonNullableType(nonOptionalType), node, nonOptionalType !== leftType); } - function checkNonNullAssertion(node: NonNullExpression) { + function checkNonNullAssertion(node: NonNullExpression, _checkMode: CheckMode | undefined) { return node.flags & NodeFlags.OptionalChain ? checkNonNullChain(node as NonNullChain) : getNonNullableType(checkExpression(node.expression)); } - function checkExpressionWithTypeArguments(node: ExpressionWithTypeArguments | TypeQueryNode) { + function checkExpressionWithTypeArguments(node: ExpressionWithTypeArguments | TypeQueryNode, checkMode: CheckMode | undefined) { checkGrammarExpressionWithTypeArguments(node); const exprType = node.kind === SyntaxKind.ExpressionWithTypeArguments ? checkExpression(node.expression) : - isThisIdentifier(node.exprName) ? checkThisExpression(node.exprName) : + isThisIdentifier(node.exprName) ? checkThisExpression(node.exprName, checkMode) : checkExpression(node.exprName); const typeArguments = node.typeArguments; if (exprType === silentNeverType || isErrorType(exprType) || !some(typeArguments)) { @@ -32378,7 +32441,7 @@ namespace ts { } } - function checkMetaProperty(node: MetaProperty): Type { + function checkMetaProperty(node: MetaProperty, _checkMode: CheckMode | undefined): Type { checkGrammarMetaProperty(node); if (node.keywordToken === SyntaxKind.NewKeyword) { @@ -33369,7 +33432,7 @@ namespace ts { return true; } - function checkDeleteExpression(node: DeleteExpression): Type { + function checkDeleteExpression(node: DeleteExpression, _checkMode: CheckMode | undefined): Type { checkExpression(node.expression); const expr = skipParentheses(node.expression); if (!isAccessExpression(expr)) { @@ -33399,12 +33462,12 @@ namespace ts { } } - function checkTypeOfExpression(node: TypeOfExpression): Type { + function checkTypeOfExpression(node: TypeOfExpression, _checkMode: CheckMode | undefined): Type { checkExpression(node.expression); return typeofType; } - function checkVoidExpression(node: VoidExpression): Type { + function checkVoidExpression(node: VoidExpression, _checkMode: CheckMode | undefined): Type { checkExpression(node.expression); return undefinedWideningType; } @@ -33475,7 +33538,7 @@ namespace ts { } } - function checkAwaitExpression(node: AwaitExpression): Type { + function checkAwaitExpression(node: AwaitExpression, _checkMode: CheckMode | undefined): Type { addLazyDiagnostic(() => checkAwaitExpressionGrammar(node)); const operandType = checkExpression(node.expression); @@ -33486,7 +33549,7 @@ namespace ts { return awaitedType; } - function checkPrefixUnaryExpression(node: PrefixUnaryExpression): Type { + function checkPrefixUnaryExpression(node: PrefixUnaryExpression, _checkMode: CheckMode | undefined): Type { const operandType = checkExpression(node.operand); if (operandType === silentNeverType) { return silentNeverType; @@ -33545,7 +33608,7 @@ namespace ts { return errorType; } - function checkPostfixUnaryExpression(node: PostfixUnaryExpression): Type { + function checkPostfixUnaryExpression(node: PostfixUnaryExpression, _checkMode: CheckMode | undefined): Type { const operandType = checkExpression(node.operand); if (operandType === silentNeverType) { return silentNeverType; @@ -34531,7 +34594,7 @@ namespace ts { return [ effectiveLeft, effectiveRight ]; } - function checkYieldExpression(node: YieldExpression): Type { + function checkYieldExpression(node: YieldExpression, _checkMode: CheckMode | undefined): Type { addLazyDiagnostic(checkYieldExpressionGrammar); const func = getContainingFunction(node); @@ -34605,7 +34668,7 @@ namespace ts { } } - function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type { + function checkConditionalExpression(node: ConditionalExpression, checkMode: CheckMode | undefined): Type { checkTruthinessExpression(node.condition); checkTestingKnownTruthyCallableOrAwaitableType(node.condition, node.whenTrue); const type1 = checkExpression(node.whenTrue, checkMode); @@ -35085,7 +35148,7 @@ namespace ts { } } - function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type { + function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode: CheckMode | undefined): Type { if (hasJSDocNodes(node) && isJSDocTypeAssertion(node)) { const type = getJSDocTypeAssertionType(node); return checkAssertionWorker(type, type, node.expression, checkMode); @@ -35105,110 +35168,13 @@ namespace ts { cancellationToken.throwIfCancellationRequested(); } } - switch (kind) { - case SyntaxKind.Identifier: - return checkIdentifier(node as Identifier, checkMode); - case SyntaxKind.PrivateIdentifier: - return checkPrivateIdentifierExpression(node as PrivateIdentifier); - case SyntaxKind.ThisKeyword: - return checkThisExpression(node); - case SyntaxKind.SuperKeyword: - return checkSuperExpression(node); - case SyntaxKind.NullKeyword: - return nullWideningType; - case SyntaxKind.NoSubstitutionTemplateLiteral: - case SyntaxKind.StringLiteral: - return getFreshTypeOfLiteralType(getStringLiteralType((node as StringLiteralLike).text)); - case SyntaxKind.NumericLiteral: - checkGrammarNumericLiteral(node as NumericLiteral); - return getFreshTypeOfLiteralType(getNumberLiteralType(+(node as NumericLiteral).text)); - case SyntaxKind.BigIntLiteral: - checkGrammarBigIntLiteral(node as BigIntLiteral); - return getFreshTypeOfLiteralType(getBigIntLiteralType({ - negative: false, - base10Value: parsePseudoBigInt((node as BigIntLiteral).text) - })); - case SyntaxKind.TrueKeyword: - return trueType; - case SyntaxKind.FalseKeyword: - return falseType; - case SyntaxKind.TemplateExpression: - return checkTemplateExpression(node as TemplateExpression); - case SyntaxKind.RegularExpressionLiteral: - return globalRegExpType; - case SyntaxKind.ArrayLiteralExpression: - return checkArrayLiteral(node as ArrayLiteralExpression, checkMode, forceTuple); - case SyntaxKind.ObjectLiteralExpression: - return checkObjectLiteral(node as ObjectLiteralExpression, checkMode); - case SyntaxKind.PropertyAccessExpression: - return checkPropertyAccessExpression(node as PropertyAccessExpression, checkMode); - case SyntaxKind.QualifiedName: - return checkQualifiedName(node as QualifiedName, checkMode); - case SyntaxKind.ElementAccessExpression: - return checkIndexedAccess(node as ElementAccessExpression, checkMode); - case SyntaxKind.CallExpression: - if ((node as CallExpression).expression.kind === SyntaxKind.ImportKeyword) { - return checkImportCallExpression(node as ImportCall); - } - // falls through - case SyntaxKind.NewExpression: - return checkCallExpression(node as CallExpression, checkMode); - case SyntaxKind.TaggedTemplateExpression: - return checkTaggedTemplateExpression(node as TaggedTemplateExpression); - case SyntaxKind.ParenthesizedExpression: - return checkParenthesizedExpression(node as ParenthesizedExpression, checkMode); - case SyntaxKind.ClassExpression: - return checkClassExpression(node as ClassExpression); - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - return checkFunctionExpressionOrObjectLiteralMethod(node as FunctionExpression | ArrowFunction, checkMode); - case SyntaxKind.TypeOfExpression: - return checkTypeOfExpression(node as TypeOfExpression); - case SyntaxKind.TypeAssertionExpression: - case SyntaxKind.AsExpression: - return checkAssertion(node as AssertionExpression); - case SyntaxKind.NonNullExpression: - return checkNonNullAssertion(node as NonNullExpression); - case SyntaxKind.ExpressionWithTypeArguments: - return checkExpressionWithTypeArguments(node as ExpressionWithTypeArguments); - case SyntaxKind.MetaProperty: - return checkMetaProperty(node as MetaProperty); - case SyntaxKind.DeleteExpression: - return checkDeleteExpression(node as DeleteExpression); - case SyntaxKind.VoidExpression: - return checkVoidExpression(node as VoidExpression); - case SyntaxKind.AwaitExpression: - return checkAwaitExpression(node as AwaitExpression); - case SyntaxKind.PrefixUnaryExpression: - return checkPrefixUnaryExpression(node as PrefixUnaryExpression); - case SyntaxKind.PostfixUnaryExpression: - return checkPostfixUnaryExpression(node as PostfixUnaryExpression); - case SyntaxKind.BinaryExpression: - return checkBinaryExpression(node as BinaryExpression, checkMode); - case SyntaxKind.ConditionalExpression: - return checkConditionalExpression(node as ConditionalExpression, checkMode); - case SyntaxKind.SpreadElement: - return checkSpreadExpression(node as SpreadElement, checkMode); - case SyntaxKind.OmittedExpression: - return undefinedWideningType; - case SyntaxKind.YieldExpression: - return checkYieldExpression(node as YieldExpression); - case SyntaxKind.SyntheticExpression: - return checkSyntheticExpression(node as SyntheticExpression); - case SyntaxKind.JsxExpression: - return checkJsxExpression(node as JsxExpression, checkMode); - case SyntaxKind.JsxElement: - return checkJsxElement(node as JsxElement, checkMode); - case SyntaxKind.JsxSelfClosingElement: - return checkJsxSelfClosingElement(node as JsxSelfClosingElement, checkMode); - case SyntaxKind.JsxFragment: - return checkJsxFragment(node as JsxFragment); - case SyntaxKind.JsxAttributes: - return checkJsxAttributes(node as JsxAttributes, checkMode); - case SyntaxKind.JsxOpeningElement: - Debug.fail("Shouldn't ever directly check a JsxOpeningElement"); + + /** Special case array literals, since {@link checkArrayLiteral} is the only function that needs {@link forceTuple}. */ + if (kind === SyntaxKind.ArrayLiteralExpression) { + return checkArrayLiteral(node as ArrayLiteralExpression, checkMode, forceTuple); } - return errorType; + const result = checkExpressionWorkerTable[kind]?.(node, checkMode); + return result ?? errorType; } // DECLARATION AND STATEMENT TYPE CHECKING @@ -39910,7 +39876,7 @@ namespace ts { return true; } - function checkClassExpression(node: ClassExpression): Type { + function checkClassExpression(node: ClassExpression, _checkMode: CheckMode | undefined): Type { checkClassLikeDeclaration(node); checkNodeDeferred(node); return getTypeOfSymbol(getSymbolOfNode(node));