@@ -109,6 +109,7 @@ import {
109109 createDiagnosticForNodeFromMessageChain,
110110 createDiagnosticMessageChainFromDiagnostic,
111111 createEmptyExports,
112+ createEvaluator,
112113 createFileDiagnostic,
113114 createGetCanonicalFileName,
114115 createGetSymbolWalker,
@@ -1477,6 +1478,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
14771478 var checkBinaryExpression = createCheckBinaryExpression();
14781479 var emitResolver = createResolver();
14791480 var nodeBuilder = createNodeBuilder();
1481+ var evaluate = createEvaluator({
1482+ evaluateElementAccessExpression,
1483+ evaluateEntityNameExpression,
1484+ });
14801485
14811486 var globals = createSymbolTable();
14821487 var undefinedSymbol = createSymbol(SymbolFlags.Property, "undefined" as __String);
@@ -39331,7 +39336,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3933139336 if (isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType)) {
3933239337 return getTemplateLiteralType(texts, types);
3933339338 }
39334- const evaluated = node.parent.kind !== SyntaxKind.TaggedTemplateExpression && evaluateTemplateExpression (node);
39339+ const evaluated = node.parent.kind !== SyntaxKind.TaggedTemplateExpression && evaluate (node);
3933539340 return evaluated ? getFreshTypeOfLiteralType(getStringLiteralType(evaluated)) : stringType;
3933639341 }
3933739342
@@ -45828,108 +45833,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4582845833 return false;
4582945834 }
4583045835
45831- function evaluate(expr: Expression, location?: Declaration): string | number | undefined {
45832- switch (expr.kind) {
45833- case SyntaxKind.PrefixUnaryExpression:
45834- const value = evaluate((expr as PrefixUnaryExpression).operand, location);
45835- if (typeof value === "number") {
45836- switch ((expr as PrefixUnaryExpression).operator) {
45837- case SyntaxKind.PlusToken:
45838- return value;
45839- case SyntaxKind.MinusToken:
45840- return -value;
45841- case SyntaxKind.TildeToken:
45842- return ~value;
45843- }
45844- }
45845- break;
45846- case SyntaxKind.BinaryExpression:
45847- const left = evaluate((expr as BinaryExpression).left, location);
45848- const right = evaluate((expr as BinaryExpression).right, location);
45849- if (typeof left === "number" && typeof right === "number") {
45850- switch ((expr as BinaryExpression).operatorToken.kind) {
45851- case SyntaxKind.BarToken:
45852- return left | right;
45853- case SyntaxKind.AmpersandToken:
45854- return left & right;
45855- case SyntaxKind.GreaterThanGreaterThanToken:
45856- return left >> right;
45857- case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
45858- return left >>> right;
45859- case SyntaxKind.LessThanLessThanToken:
45860- return left << right;
45861- case SyntaxKind.CaretToken:
45862- return left ^ right;
45863- case SyntaxKind.AsteriskToken:
45864- return left * right;
45865- case SyntaxKind.SlashToken:
45866- return left / right;
45867- case SyntaxKind.PlusToken:
45868- return left + right;
45869- case SyntaxKind.MinusToken:
45870- return left - right;
45871- case SyntaxKind.PercentToken:
45872- return left % right;
45873- case SyntaxKind.AsteriskAsteriskToken:
45874- return left ** right;
45875- }
45876- }
45877- else if (
45878- (typeof left === "string" || typeof left === "number") &&
45879- (typeof right === "string" || typeof right === "number") &&
45880- (expr as BinaryExpression).operatorToken.kind === SyntaxKind.PlusToken
45881- ) {
45882- return "" + left + right;
45883- }
45884- break;
45885- case SyntaxKind.StringLiteral:
45886- case SyntaxKind.NoSubstitutionTemplateLiteral:
45887- return (expr as StringLiteralLike).text;
45888- case SyntaxKind.TemplateExpression:
45889- return evaluateTemplateExpression(expr as TemplateExpression, location);
45890- case SyntaxKind.NumericLiteral:
45891- checkGrammarNumericLiteral(expr as NumericLiteral);
45892- return +(expr as NumericLiteral).text;
45893- case SyntaxKind.ParenthesizedExpression:
45894- return evaluate((expr as ParenthesizedExpression).expression, location);
45895- case SyntaxKind.Identifier: {
45896- const identifier = expr as Identifier;
45897- if (isInfinityOrNaNString(identifier.escapedText) && (resolveEntityName(identifier, SymbolFlags.Value, /*ignoreErrors*/ true) === getGlobalSymbol(identifier.escapedText, SymbolFlags.Value, /*diagnostic*/ undefined))) {
45898- return +(identifier.escapedText);
45899- }
45900- // falls through
45836+ function evaluateEntityNameExpression(expr: EntityNameExpression, location?: Declaration) {
45837+ const symbol = resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true);
45838+ if (!symbol) return undefined;
45839+
45840+ if (expr.kind === SyntaxKind.Identifier) {
45841+ const identifier = expr;
45842+ if (isInfinityOrNaNString(identifier.escapedText) && (symbol === getGlobalSymbol(identifier.escapedText, SymbolFlags.Value, /*diagnostic*/ undefined))) {
45843+ return +(identifier.escapedText);
4590145844 }
45902- case SyntaxKind.PropertyAccessExpression:
45903- if (isEntityNameExpression(expr)) {
45904- const symbol = resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true);
45905- if (symbol) {
45906- if (symbol.flags & SymbolFlags.EnumMember) {
45907- return location ? evaluateEnumMember(expr, symbol, location) : getEnumMemberValue(symbol.valueDeclaration as EnumMember);
45908- }
45909- if (isConstantVariable(symbol)) {
45910- const declaration = symbol.valueDeclaration;
45911- if (declaration && isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && (!location || declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location))) {
45912- return evaluate(declaration.initializer, declaration);
45913- }
45914- }
45915- }
45916- }
45917- break;
45918- case SyntaxKind.ElementAccessExpression:
45919- const root = (expr as ElementAccessExpression).expression;
45920- if (isEntityNameExpression(root) && isStringLiteralLike((expr as ElementAccessExpression).argumentExpression)) {
45921- const rootSymbol = resolveEntityName(root, SymbolFlags.Value, /*ignoreErrors*/ true);
45922- if (rootSymbol && rootSymbol.flags & SymbolFlags.Enum) {
45923- const name = escapeLeadingUnderscores(((expr as ElementAccessExpression).argumentExpression as StringLiteralLike).text);
45924- const member = rootSymbol.exports!.get(name);
45925- if (member) {
45926- return location ? evaluateEnumMember(expr, member, location) : getEnumMemberValue(member.valueDeclaration as EnumMember);
45927- }
45928- }
45845+ }
45846+
45847+ if (symbol.flags & SymbolFlags.EnumMember) {
45848+ return location ? evaluateEnumMember(expr, symbol, location) : getEnumMemberValue(symbol.valueDeclaration as EnumMember);
45849+ }
45850+ if (isConstantVariable(symbol)) {
45851+ const declaration = symbol.valueDeclaration;
45852+ if (declaration && isVariableDeclaration(declaration) && !declaration.type && declaration.initializer && (!location || declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location))) {
45853+ return evaluate(declaration.initializer, declaration);
45854+ }
45855+ }
45856+ }
45857+
45858+ function evaluateElementAccessExpression(expr: ElementAccessExpression, location?: Declaration) {
45859+ const root = expr.expression;
45860+ if (isEntityNameExpression(root) && isStringLiteralLike(expr.argumentExpression)) {
45861+ const rootSymbol = resolveEntityName(root, SymbolFlags.Value, /*ignoreErrors*/ true);
45862+ if (rootSymbol && rootSymbol.flags & SymbolFlags.Enum) {
45863+ const name = escapeLeadingUnderscores(expr.argumentExpression.text);
45864+ const member = rootSymbol.exports!.get(name);
45865+ if (member) {
45866+ return location ? evaluateEnumMember(expr, member, location) : getEnumMemberValue(member.valueDeclaration as EnumMember);
4592945867 }
45930- break;
45868+ }
4593145869 }
45932- return undefined;
4593345870 }
4593445871
4593545872 function evaluateEnumMember(expr: Expression, symbol: Symbol, location: Declaration) {
@@ -45945,19 +45882,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
4594545882 return getEnumMemberValue(declaration as EnumMember);
4594645883 }
4594745884
45948- function evaluateTemplateExpression(expr: TemplateExpression, location?: Declaration) {
45949- let result = expr.head.text;
45950- for (const span of expr.templateSpans) {
45951- const value = evaluate(span.expression, location);
45952- if (value === undefined) {
45953- return undefined;
45954- }
45955- result += value;
45956- result += span.literal.text;
45957- }
45958- return result;
45959- }
45960-
4596145885 function checkEnumDeclaration(node: EnumDeclaration) {
4596245886 addLazyDiagnostic(() => checkEnumDeclarationWorker(node));
4596345887 }
0 commit comments