Evaluate simple template expressions (#53907)

This commit is contained in:
Mateusz Burzyński
2023-05-15 21:51:06 +02:00
committed by GitHub
parent dad9ae0ce8
commit cb88998063
104 changed files with 815 additions and 535 deletions

View File

@@ -29303,6 +29303,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
case SyntaxKind.NumericLiteral:
case SyntaxKind.BigIntLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateExpression:
case SyntaxKind.TrueKeyword:
case SyntaxKind.FalseKeyword:
case SyntaxKind.NullKeyword:
@@ -37355,7 +37356,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
texts.push(span.literal.text);
types.push(isTypeAssignableTo(type, templateConstraintType) ? type : stringType);
}
return isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType) ? getTemplateLiteralType(texts, types) : stringType;
if (isConstContext(node) || isTemplateLiteralContext(node) || someType(getContextualType(node, /*contextFlags*/ undefined) || unknownType, isTemplateLiteralContextualType)) {
return getTemplateLiteralType(texts, types);
}
const evaluated = node.parent.kind !== SyntaxKind.TaggedTemplateExpression && evaluateTemplateExpression(node);
return evaluated ? getFreshTypeOfLiteralType(getStringLiteralType(evaluated)) : stringType;
}
function isTemplateLiteralContextualType(type: Type): boolean {
@@ -43632,7 +43637,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return value;
}
function evaluate(expr: Expression, location: Declaration): string | number | undefined {
function evaluate(expr: Expression, location?: Declaration): string | number | undefined {
switch (expr.kind) {
case SyntaxKind.PrefixUnaryExpression:
const value = evaluate((expr as PrefixUnaryExpression).operand, location);
@@ -43689,11 +43694,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const symbol = resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true);
if (symbol) {
if (symbol.flags & SymbolFlags.EnumMember) {
return evaluateEnumMember(expr, symbol, location);
return location ? evaluateEnumMember(expr, symbol, location) : getEnumMemberValue(symbol.valueDeclaration as EnumMember);
}
if (isConstVariable(symbol)) {
const declaration = symbol.valueDeclaration as VariableDeclaration | undefined;
if (declaration && !declaration.type && declaration.initializer && declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location)) {
if (declaration && !declaration.type && declaration.initializer && (!location || declaration !== location && isBlockScopedNameDeclaredBeforeUse(declaration, location))) {
return evaluate(declaration.initializer, declaration);
}
}
@@ -43708,7 +43713,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const name = escapeLeadingUnderscores(((expr as ElementAccessExpression).argumentExpression as StringLiteralLike).text);
const member = rootSymbol.exports!.get(name);
if (member) {
return evaluateEnumMember(expr, member, location);
return location ? evaluateEnumMember(expr, member, location) : getEnumMemberValue(member.valueDeclaration as EnumMember);
}
}
}
@@ -43730,7 +43735,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return getEnumMemberValue(declaration as EnumMember);
}
function evaluateTemplateExpression(expr: TemplateExpression, location: Declaration) {
function evaluateTemplateExpression(expr: TemplateExpression, location?: Declaration) {
let result = expr.head.text;
for (const span of expr.templateSpans) {
const value = evaluate(span.expression, location);