Merge pull request #5725 from Microsoft/stringTypesCleanup

Disambiguate string literal types from other string literals.
This commit is contained in:
Ron Buckton
2015-11-24 15:23:25 -08:00
8 changed files with 72 additions and 48 deletions
+13 -13
View File
@@ -532,7 +532,7 @@ namespace ts {
}
// Because of module/namespace merging, a module's exports are in scope,
// yet we never want to treat an export specifier as putting a member in scope.
// yet we never want to treat an export specifier as putting a member in scope.
// Therefore, if the name we find is purely an export specifier, it is not actually considered in scope.
// Two things to note about this:
// 1. We have to check this without calling getSymbol. The problem with calling getSymbol
@@ -3197,7 +3197,7 @@ namespace ts {
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.StringLiteral:
case SyntaxKind.StringLiteralType:
return true;
case SyntaxKind.ArrayType:
return isIndependentType((<ArrayTypeNode>node).elementType);
@@ -3858,7 +3858,7 @@ namespace ts {
paramSymbol = resolvedSymbol;
}
parameters.push(paramSymbol);
if (param.type && param.type.kind === SyntaxKind.StringLiteral) {
if (param.type && param.type.kind === SyntaxKind.StringLiteralType) {
hasStringLiterals = true;
}
@@ -4527,8 +4527,7 @@ namespace ts {
return links.resolvedType;
}
function getStringLiteralType(node: StringLiteral): StringLiteralType {
const text = node.text;
function getStringLiteralType(text: string): StringLiteralType {
if (hasProperty(stringLiteralTypes, text)) {
return stringLiteralTypes[text];
}
@@ -4538,10 +4537,10 @@ namespace ts {
return type;
}
function getTypeFromStringLiteral(node: StringLiteral): Type {
function getTypeFromStringLiteral(node: StringLiteral | StringLiteralTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = getStringLiteralType(node);
links.resolvedType = getStringLiteralType(node.text);
}
return links.resolvedType;
}
@@ -4583,8 +4582,8 @@ namespace ts {
return voidType;
case SyntaxKind.ThisType:
return getTypeFromThisTypeNode(node);
case SyntaxKind.StringLiteral:
return getTypeFromStringLiteral(<StringLiteral>node);
case SyntaxKind.StringLiteralType:
return getTypeFromStringLiteral(<StringLiteralTypeNode>node);
case SyntaxKind.TypeReference:
return getTypeFromTypeReference(<TypeReferenceNode>node);
case SyntaxKind.TypePredicate:
@@ -8791,7 +8790,7 @@ namespace ts {
// for the argument. In that case, we should check the argument.
if (argType === undefined) {
argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors
? getStringLiteralType(<StringLiteral>arg)
? getStringLiteralType((<StringLiteral>arg).text)
: checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
}
@@ -8986,7 +8985,7 @@ namespace ts {
case SyntaxKind.Identifier:
case SyntaxKind.NumericLiteral:
case SyntaxKind.StringLiteral:
return getStringLiteralType(<StringLiteral>element.name);
return getStringLiteralType((<Identifier | LiteralExpression>element.name).text);
case SyntaxKind.ComputedPropertyName:
const nameType = checkComputedPropertyName(<ComputedPropertyName>element.name);
@@ -10608,7 +10607,8 @@ namespace ts {
function checkStringLiteralExpression(node: StringLiteral): Type {
const contextualType = getContextualType(node);
if (contextualType && contextualTypeIsStringLiteralType(contextualType)) {
return getStringLiteralType(node);
// TODO (drosen): Consider using getTypeFromStringLiteral instead
return getStringLiteralType(node.text);
}
return stringType;
@@ -11442,7 +11442,7 @@ namespace ts {
// we can get here in two cases
// 1. mixed static and instance class members
// 2. something with the same name was defined before the set of overloads that prevents them from merging
// here we'll report error only for the first case since for second we should already report error in binder
// here we'll report error only for the first case since for second we should already report error in binder
if (reportError) {
const diagnostic = node.flags & NodeFlags.Static ? Diagnostics.Function_overload_must_be_static : Diagnostics.Function_overload_must_not_be_static;
error(errorNode, diagnostic);
+1 -1
View File
@@ -357,7 +357,7 @@ namespace ts {
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.ThisType:
case SyntaxKind.StringLiteral:
case SyntaxKind.StringLiteralType:
return writeTextOfNode(currentText, type);
case SyntaxKind.ExpressionWithTypeArguments:
return emitExpressionWithTypeArguments(<ExpressionWithTypeArguments>type);
+5 -6
View File
@@ -1276,7 +1276,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
}
function isBinaryOrOctalIntegerLiteral(node: LiteralExpression, text: string): boolean {
function isBinaryOrOctalIntegerLiteral(node: LiteralLikeNode, text: string): boolean {
if (node.kind === SyntaxKind.NumericLiteral && text.length > 1) {
switch (text.charCodeAt(1)) {
case CharacterCodes.b:
@@ -1290,7 +1290,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
return false;
}
function emitLiteral(node: LiteralExpression) {
function emitLiteral(node: LiteralExpression | TemplateLiteralFragment) {
const text = getLiteralText(node);
if ((compilerOptions.sourceMap || compilerOptions.inlineSourceMap) && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) {
@@ -1305,7 +1305,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
}
}
function getLiteralText(node: LiteralExpression) {
function getLiteralText(node: LiteralExpression | TemplateLiteralFragment) {
// Any template literal or string literal with an extended escape
// (e.g. "\u{0067}") will need to be downleveled as a escaped string literal.
if (languageVersion < ScriptTarget.ES6 && (isTemplateLiteralKind(node.kind) || node.hasExtendedUnicodeEscape)) {
@@ -1364,7 +1364,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
write(`"${text}"`);
}
function emitDownlevelTaggedTemplateArray(node: TaggedTemplateExpression, literalEmitter: (literal: LiteralExpression) => void) {
function emitDownlevelTaggedTemplateArray(node: TaggedTemplateExpression, literalEmitter: (literal: LiteralExpression | TemplateLiteralFragment) => void) {
write("[");
if (node.template.kind === SyntaxKind.NoSubstitutionTemplateLiteral) {
literalEmitter(<LiteralExpression>node.template);
@@ -5954,7 +5954,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
function emitSerializedTypeNode(node: TypeNode) {
if (node) {
switch (node.kind) {
case SyntaxKind.VoidKeyword:
write("void 0");
@@ -5980,7 +5979,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
return;
case SyntaxKind.StringKeyword:
case SyntaxKind.StringLiteral:
case SyntaxKind.StringLiteralType:
write("String");
return;
+18 -6
View File
@@ -1874,7 +1874,7 @@ namespace ts {
function parseTemplateExpression(): TemplateExpression {
const template = <TemplateExpression>createNode(SyntaxKind.TemplateExpression);
template.head = parseLiteralNode();
template.head = parseTemplateLiteralFragment();
Debug.assert(template.head.kind === SyntaxKind.TemplateHead, "Template head has wrong token kind");
const templateSpans = <NodeArray<TemplateSpan>>[];
@@ -1895,22 +1895,34 @@ namespace ts {
const span = <TemplateSpan>createNode(SyntaxKind.TemplateSpan);
span.expression = allowInAnd(parseExpression);
let literal: LiteralExpression;
let literal: TemplateLiteralFragment;
if (token === SyntaxKind.CloseBraceToken) {
reScanTemplateToken();
literal = parseLiteralNode();
literal = parseTemplateLiteralFragment();
}
else {
literal = <LiteralExpression>parseExpectedToken(SyntaxKind.TemplateTail, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken));
literal = <TemplateLiteralFragment>parseExpectedToken(SyntaxKind.TemplateTail, /*reportAtCurrentPosition*/ false, Diagnostics._0_expected, tokenToString(SyntaxKind.CloseBraceToken));
}
span.literal = literal;
return finishNode(span);
}
function parseStringLiteralTypeNode(): StringLiteralTypeNode {
return <StringLiteralTypeNode>parseLiteralLikeNode(SyntaxKind.StringLiteralType, /*internName*/ true);
}
function parseLiteralNode(internName?: boolean): LiteralExpression {
const node = <LiteralExpression>createNode(token);
return <LiteralExpression>parseLiteralLikeNode(token, internName);
}
function parseTemplateLiteralFragment(): TemplateLiteralFragment {
return <TemplateLiteralFragment>parseLiteralLikeNode(token, /*internName*/ false);
}
function parseLiteralLikeNode(kind: SyntaxKind, internName: boolean): LiteralLikeNode {
const node = <LiteralExpression>createNode(kind);
const text = scanner.getTokenValue();
node.text = internName ? internIdentifier(text) : text;
@@ -2397,7 +2409,7 @@ namespace ts {
const node = tryParse(parseKeywordAndNoDot);
return node || parseTypeReferenceOrTypePredicate();
case SyntaxKind.StringLiteral:
return <StringLiteral>parseLiteralNode(/*internName*/ true);
return parseStringLiteralTypeNode();
case SyntaxKind.VoidKeyword:
return parseTokenNode<TypeNode>();
case SyntaxKind.ThisKeyword:
+22 -10
View File
@@ -205,6 +205,7 @@ namespace ts {
IntersectionType,
ParenthesizedType,
ThisType,
StringLiteralType,
// Binding patterns
ObjectBindingPattern,
ArrayBindingPattern,
@@ -350,7 +351,7 @@ namespace ts {
FirstFutureReservedWord = ImplementsKeyword,
LastFutureReservedWord = YieldKeyword,
FirstTypeNode = TypePredicate,
LastTypeNode = ThisType,
LastTypeNode = StringLiteralType,
FirstPunctuation = OpenBraceToken,
LastPunctuation = CaretEqualsToken,
FirstToken = Unknown,
@@ -790,10 +791,13 @@ namespace ts {
type: TypeNode;
}
// Note that a StringLiteral AST node is both an Expression and a TypeNode. The latter is
// because string literals can appear in type annotations as well.
// @kind(SyntaxKind.StringLiteralType)
export interface StringLiteralTypeNode extends LiteralLikeNode, TypeNode {
_stringLiteralTypeBrand: any;
}
// @kind(SyntaxKind.StringLiteral)
export interface StringLiteral extends LiteralExpression, TypeNode {
export interface StringLiteral extends LiteralExpression {
_stringLiteralBrand: any;
}
@@ -911,24 +915,32 @@ namespace ts {
body: ConciseBody;
}
export interface LiteralLikeNode extends Node {
text: string;
isUnterminated?: boolean;
hasExtendedUnicodeEscape?: boolean;
}
// The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral,
// or any literal of a template, this means quotes have been removed and escapes have been converted to actual characters.
// For a NumericLiteral, the stored value is the toString() representation of the number. For example 1, 1.00, and 1e0 are all stored as just "1".
// @kind(SyntaxKind.NumericLiteral)
// @kind(SyntaxKind.RegularExpressionLiteral)
// @kind(SyntaxKind.NoSubstitutionTemplateLiteral)
export interface LiteralExpression extends LiteralLikeNode, PrimaryExpression {
_literalExpressionBrand: any;
}
// @kind(SyntaxKind.TemplateHead)
// @kind(SyntaxKind.TemplateMiddle)
// @kind(SyntaxKind.TemplateTail)
export interface LiteralExpression extends PrimaryExpression {
text: string;
isUnterminated?: boolean;
hasExtendedUnicodeEscape?: boolean;
export interface TemplateLiteralFragment extends LiteralLikeNode {
_templateLiteralFragmentBrand: any;
}
// @kind(SyntaxKind.TemplateExpression)
export interface TemplateExpression extends PrimaryExpression {
head: LiteralExpression;
head: TemplateLiteralFragment;
templateSpans: NodeArray<TemplateSpan>;
}
@@ -937,7 +949,7 @@ namespace ts {
// @kind(SyntaxKind.TemplateSpan)
export interface TemplateSpan extends Node {
expression: Expression;
literal: LiteralExpression;
literal: TemplateLiteralFragment;
}
// @kind(SyntaxKind.ParenthesizedExpression)
-3
View File
@@ -466,9 +466,6 @@ namespace ts {
return true;
case SyntaxKind.VoidKeyword:
return node.parent.kind !== SyntaxKind.VoidExpression;
case SyntaxKind.StringLiteral:
// Specialized signatures can have string literals as their parameters' type names
return node.parent.kind === SyntaxKind.Parameter;
case SyntaxKind.ExpressionWithTypeArguments:
return !isExpressionWithTypeArgumentsInClassExtendsClause(node);