Switch to 'unique symbol'

This commit is contained in:
Ron Buckton
2017-10-04 19:34:29 -07:00
parent 43c151a9df
commit ee23f93275
70 changed files with 1291 additions and 1304 deletions
+80 -74
View File
@@ -2497,7 +2497,7 @@ namespace ts {
return (<IntrinsicType>type).intrinsicName === "true" ? createTrue() : createFalse();
}
if (type.flags & TypeFlags.UniqueESSymbol) {
return createESSymbolTypeNode();
return createTypeOperatorNode(SyntaxKind.UniqueKeyword, createKeywordTypeNode(SyntaxKind.SymbolKeyword));
}
if (type.flags & TypeFlags.Void) {
return createKeywordTypeNode(SyntaxKind.VoidKeyword);
@@ -3313,9 +3313,9 @@ namespace ts {
writeAnonymousType(<ObjectType>type, nextFlags);
}
else if (type.flags & TypeFlags.UniqueESSymbol) {
writeKeyword(writer, SyntaxKind.UniqueKeyword);
writeSpace(writer);
writeKeyword(writer, SyntaxKind.SymbolKeyword);
writePunctuation(writer, SyntaxKind.OpenParenToken);
writePunctuation(writer, SyntaxKind.CloseParenToken);
}
else if (type.flags & TypeFlags.StringOrNumberLiteral) {
writer.writeStringLiteral(literalTypeToString(<LiteralType>type));
@@ -4533,7 +4533,7 @@ namespace ts {
reportErrorsFromWidening(declaration, type);
}
// always widen a unique 'symbol()' type if the type was created for a different declaration.
// always widen a 'unique symbol' type if the type was created for a different declaration.
if (type.flags & TypeFlags.UniqueESSymbol && !declaration.type && type.symbol !== getSymbolOfNode(declaration)) {
type = esSymbolType;
}
@@ -5949,7 +5949,9 @@ namespace ts {
const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T'
const templateReadonly = !!type.declaration.readonlyToken;
const templateOptional = !!type.declaration.questionToken;
if (type.declaration.typeParameter.constraint.kind === SyntaxKind.TypeOperator) {
const constraintDeclaration = type.declaration.typeParameter.constraint;
if (constraintDeclaration.kind === SyntaxKind.TypeOperator &&
(<TypeOperatorNode>constraintDeclaration).operator === SyntaxKind.KeyOfKeyword) {
// We have a { [P in keyof T]: X }
for (const propertySymbol of getPropertiesOfType(modifiersType)) {
addMemberForKeyType(getLiteralTypeFromPropertyName(propertySymbol), propertySymbol);
@@ -6024,7 +6026,8 @@ namespace ts {
function getModifiersTypeFromMappedType(type: MappedType) {
if (!type.modifiersType) {
const constraintDeclaration = type.declaration.typeParameter.constraint;
if (constraintDeclaration.kind === SyntaxKind.TypeOperator) {
if (constraintDeclaration.kind === SyntaxKind.TypeOperator &&
(<TypeOperatorNode>constraintDeclaration).operator === SyntaxKind.KeyOfKeyword) {
// If the constraint declaration is a 'keyof T' node, the modifiers type is T. We check
// AST nodes here because, when T is a non-generic type, the logic below eagerly resolves
// 'keyof T' to a literal union type and we can't recover T from that type.
@@ -7822,7 +7825,21 @@ namespace ts {
function getTypeFromTypeOperatorNode(node: TypeOperatorNode) {
const links = getNodeLinks(node);
if (!links.resolvedType) {
links.resolvedType = getIndexType(getTypeFromTypeNode(node.type));
switch (node.operator) {
case SyntaxKind.KeyOfKeyword:
links.resolvedType = getIndexType(getTypeFromTypeNode(node.type));
break;
case SyntaxKind.UniqueKeyword:
if (node.type.kind === SyntaxKind.SymbolKeyword) {
const parent = skipParentheses(node).parent;
const symbol = getSymbolOfNode(parent);
links.resolvedType = symbol ? getUniqueESSymbolTypeForSymbol(symbol) : esSymbolType;
}
else {
links.resolvedType = unknownType;
}
break;
}
}
return links.resolvedType;
}
@@ -8226,21 +8243,6 @@ namespace ts {
return esSymbolType;
}
function getTypeFromESSymbolTypeNode(node: ESSymbolTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
const parent = skipParentheses(node).parent;
const symbol = getSymbolOfNode(parent);
if (symbol) {
links.resolvedType = getUniqueESSymbolTypeForSymbol(symbol);
}
else {
links.resolvedType = esSymbolType;
}
}
return links.resolvedType;
}
function getTypeFromJSDocVariadicType(node: JSDocVariadicType): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
@@ -8300,8 +8302,6 @@ namespace ts {
return getTypeFromThisTypeNode(node as ThisExpression | ThisTypeNode);
case SyntaxKind.LiteralType:
return getTypeFromLiteralTypeNode(<LiteralTypeNode>node);
case SyntaxKind.ESSymbolType:
return getTypeFromESSymbolTypeNode(<ESSymbolTypeNode>node);
case SyntaxKind.TypeReference:
return getTypeFromTypeReference(<TypeReferenceNode>node);
case SyntaxKind.TypePredicate:
@@ -17313,7 +17313,7 @@ namespace ts {
type = checkAwaitedType(type, /*errorNode*/ func, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
}
// widen 'symbol()' types when we infer the return type.
// widen 'unique symbol' types when we infer the return type.
type = getWidenedTypeOfUniqueESSymbolType(type);
}
else {
@@ -17349,7 +17349,7 @@ namespace ts {
// Return a union of the return expression types.
type = getUnionType(types, /*subtypeReduction*/ true);
// widen 'symbol()' types when we infer the return type.
// widen 'unique symbol' types when we infer the return type.
type = getWidenedTypeOfUniqueESSymbolType(type);
if (functionFlags & FunctionFlags.Generator) { // AsyncGenerator function or Generator function
@@ -19428,8 +19428,9 @@ namespace ts {
checkTypeAssignableTo(constraintType, stringType, node.typeParameter.constraint);
}
function checkSymbolType(node: ESSymbolTypeNode) {
checkGrammarESSymbolTypeNode(node);
function checkTypeOperator(node: TypeOperatorNode) {
checkGrammarTypeOperatorNode(node);
checkSourceElement(node.type);
}
function isPrivateWithinAmbient(node: Node): boolean {
@@ -23000,8 +23001,9 @@ namespace ts {
case SyntaxKind.IntersectionType:
return checkUnionOrIntersectionType(<UnionOrIntersectionTypeNode>node);
case SyntaxKind.ParenthesizedType:
case SyntaxKind.TypeOperator:
return checkSourceElement((<ParenthesizedTypeNode | TypeOperatorNode>node).type);
case SyntaxKind.TypeOperator:
return checkTypeOperator(<TypeOperatorNode>node);
case SyntaxKind.JSDocAugmentsTag:
return checkJSDocAugmentsTag(node as JSDocAugmentsTag);
case SyntaxKind.JSDocTypedefTag:
@@ -23026,8 +23028,6 @@ namespace ts {
return checkIndexedAccessType(<IndexedAccessTypeNode>node);
case SyntaxKind.MappedType:
return checkMappedType(<MappedTypeNode>node);
case SyntaxKind.ESSymbolType:
return checkSymbolType(<ESSymbolTypeNode>node);
case SyntaxKind.FunctionDeclaration:
return checkFunctionDeclaration(<FunctionDeclaration>node);
case SyntaxKind.Block:
@@ -25341,54 +25341,60 @@ namespace ts {
}
}
function checkGrammarESSymbolTypeNode(node: ESSymbolTypeNode) {
let parent = node.parent;
while (parent.kind === SyntaxKind.ParenthesizedType) {
parent = parent.parent;
}
function checkGrammarTypeOperatorNode(node: TypeOperatorNode) {
if (node.operator === SyntaxKind.UniqueKeyword) {
if (node.type.kind !== SyntaxKind.SymbolKeyword) {
return grammarErrorOnNode(node.type, Diagnostics._0_expected, tokenToString(SyntaxKind.SymbolKeyword));
}
switch (parent.kind) {
case SyntaxKind.VariableDeclaration:
const decl = parent as VariableDeclaration;
if (decl.name.kind !== SyntaxKind.Identifier) {
return grammarErrorOnNode(node, Diagnostics.Unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name);
}
if (!isVariableDeclarationInVariableStatement(decl)) {
return grammarErrorOnNode(node, Diagnostics.Unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement);
}
if (!(decl.parent.flags & NodeFlags.Const)) {
return grammarErrorOnNode((<VariableDeclaration>parent).name, Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const);
}
break;
let parent = node.parent;
while (parent.kind === SyntaxKind.ParenthesizedType) {
parent = parent.parent;
}
case SyntaxKind.PropertyDeclaration:
if (!hasModifier(parent, ModifierFlags.Static) ||
!hasModifier(parent, ModifierFlags.Readonly)) {
return grammarErrorOnNode((<PropertyDeclaration>parent).name, Diagnostics.A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly);
}
break;
switch (parent.kind) {
case SyntaxKind.VariableDeclaration:
const decl = parent as VariableDeclaration;
if (decl.name.kind !== SyntaxKind.Identifier) {
return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_may_not_be_used_on_a_variable_declaration_with_a_binding_name);
}
if (!isVariableDeclarationInVariableStatement(decl)) {
return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_only_allowed_on_variables_in_a_variable_statement);
}
if (!(decl.parent.flags & NodeFlags.Const)) {
return grammarErrorOnNode((<VariableDeclaration>parent).name, Diagnostics.A_variable_whose_type_is_a_unique_symbol_type_must_be_const);
}
break;
case SyntaxKind.PropertySignature:
if (!hasModifier(parent, ModifierFlags.Readonly)) {
return grammarErrorOnNode((<PropertySignature>parent).name, Diagnostics.A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly);
}
break;
case SyntaxKind.PropertyDeclaration:
if (!hasModifier(parent, ModifierFlags.Static) ||
!hasModifier(parent, ModifierFlags.Readonly)) {
return grammarErrorOnNode((<PropertyDeclaration>parent).name, Diagnostics.A_property_of_a_class_whose_type_is_a_unique_symbol_type_must_be_both_static_and_readonly);
}
break;
// report specific errors for cases where a `symbol()` type is disallowed even when it is in a `const` or `readonly` declaration.
case SyntaxKind.UnionType:
return grammarErrorOnNode(node, Diagnostics.Unique_symbol_types_are_not_allowed_in_a_union_type);
case SyntaxKind.IntersectionType:
return grammarErrorOnNode(node, Diagnostics.Unique_symbol_types_are_not_allowed_in_an_intersection_type);
case SyntaxKind.ArrayType:
return grammarErrorOnNode(node, Diagnostics.Unique_symbol_types_are_not_allowed_in_an_array_type);
case SyntaxKind.TupleType:
return grammarErrorOnNode(node, Diagnostics.Unique_symbol_types_are_not_allowed_in_a_tuple_type);
case SyntaxKind.MappedType:
return grammarErrorOnNode(node, Diagnostics.Unique_symbol_types_are_not_allowed_in_a_mapped_type);
case SyntaxKind.PropertySignature:
if (!hasModifier(parent, ModifierFlags.Readonly)) {
return grammarErrorOnNode((<PropertySignature>parent).name, Diagnostics.A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly);
}
break;
// report a general error for any other invalid use site.
default:
return grammarErrorOnNode(node, Diagnostics.Unique_symbol_types_are_not_allowed_here);
// report specific errors for cases where a `unique symbol` type is disallowed even when it is in a `const` or `readonly` declaration.
case SyntaxKind.UnionType:
return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_in_a_union_type);
case SyntaxKind.IntersectionType:
return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_in_an_intersection_type);
case SyntaxKind.ArrayType:
return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_in_an_array_type);
case SyntaxKind.TupleType:
return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_in_a_tuple_type);
case SyntaxKind.MappedType:
return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_in_a_mapped_type);
// report a general error for any other invalid use site.
default:
return grammarErrorOnNode(node, Diagnostics.unique_symbol_types_are_not_allowed_here);
}
}
}
-2
View File
@@ -425,8 +425,6 @@ namespace ts {
case SyntaxKind.ThisType:
case SyntaxKind.LiteralType:
return writeTextOfNode(currentText, type);
case SyntaxKind.ESSymbolType:
return write("symbol()");
case SyntaxKind.ExpressionWithTypeArguments:
return emitExpressionWithTypeArguments(<ExpressionWithTypeArguments>type);
case SyntaxKind.TypeReference:
+16 -16
View File
@@ -491,23 +491,23 @@
"category": "Error",
"code": 1164
},
"A computed property name in an ambient context must refer to an expression whose type is a literal type or a unique 'symbol()' type.": {
"A computed property name in an ambient context must refer to an expression whose type is a literal type or a 'unique symbol' type.": {
"category": "Error",
"code": 1165
},
"A computed property name in a class property declaration must refer to an expression whose type is a literal type or a unique 'symbol()' type.": {
"A computed property name in a class property declaration must refer to an expression whose type is a literal type or a 'unique symbol' type.": {
"category": "Error",
"code": 1166
},
"A computed property name in a method overload must refer to an expression whose type is a literal type or a unique 'symbol()' type.": {
"A computed property name in a method overload must refer to an expression whose type is a literal type or a 'unique symbol' type.": {
"category": "Error",
"code": 1168
},
"A computed property name in an interface must refer to an expression whose type is a literal type or a unique 'symbol()' type.": {
"A computed property name in an interface must refer to an expression whose type is a literal type or a 'unique symbol' type.": {
"category": "Error",
"code": 1169
},
"A computed property name in a type literal must refer to an expression whose type is a literal type or a unique 'symbol()' type.": {
"A computed property name in a type literal must refer to an expression whose type is a literal type or a 'unique symbol' type.": {
"category": "Error",
"code": 1170
},
@@ -907,47 +907,47 @@
"category": "Error",
"code": 1328
},
"Unique 'symbol()' types are not allowed in a union type.": {
"'unique symbol' types are not allowed in a union type.": {
"category": "Error",
"code": 1329
},
"Unique 'symbol()' types are not allowed in an intersection type.": {
"'unique symbol' types are not allowed in an intersection type.": {
"category": "Error",
"code": 1330
},
"Unique 'symbol()' types are not allowed in an array type.": {
"'unique symbol' types are not allowed in an array type.": {
"category": "Error",
"code": 1331
},
"Unique 'symbol()' types are not allowed in a tuple type.": {
"'unique symbol' types are not allowed in a tuple type.": {
"category": "Error",
"code": 1332
},
"Unique 'symbol()' types are not allowed in a mapped type.": {
"'unique symbol' types are not allowed in a mapped type.": {
"category": "Error",
"code": 1333
},
"A property of an interface or type literal whose type is a unique 'symbol()' type must be 'readonly'.": {
"A property of an interface or type literal whose type is a 'unique symbol' type must be 'readonly'.": {
"category": "Error",
"code": 1334
},
"A property of a class whose type is a unique 'symbol()' type must be both 'static' and 'readonly'.": {
"A property of a class whose type is a 'unique symbol' type must be both 'static' and 'readonly'.": {
"category": "Error",
"code": 1335
},
"A variable whose type is a unique 'symbol()' type must be 'const'.": {
"A variable whose type is a 'unique symbol' type must be 'const'.": {
"category": "Error",
"code": 1336
},
"Unique 'symbol()' types may not be used on a variable declaration with a binding name.": {
"'unique symbol' types may not be used on a variable declaration with a binding name.": {
"category": "Error",
"code": 1337
},
"Unique 'symbol()' types are only allowed on variables in a variable statement.": {
"'unique symbol' types are only allowed on variables in a variable statement.": {
"category": "Error",
"code": 1338
},
"Unique 'symbol()' types are not allowed here.": {
"'unique symbol' types are not allowed here.": {
"category": "Error",
"code": 1339
},
-2
View File
@@ -574,8 +574,6 @@ namespace ts {
return emitMappedType(<MappedTypeNode>node);
case SyntaxKind.LiteralType:
return emitLiteralType(<LiteralTypeNode>node);
case SyntaxKind.ESSymbolType:
return write("symbol()");
// Binding patterns
case SyntaxKind.ObjectBindingPattern:
+6 -8
View File
@@ -730,15 +730,17 @@ namespace ts {
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
}
export function createTypeOperatorNode(type: TypeNode) {
export function createTypeOperatorNode(type: TypeNode): TypeOperatorNode;
export function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword, type: TypeNode): TypeOperatorNode;
export function createTypeOperatorNode(operatorOrType: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword | TypeNode, type?: TypeNode) {
const node = createSynthesizedNode(SyntaxKind.TypeOperator) as TypeOperatorNode;
node.operator = SyntaxKind.KeyOfKeyword;
node.type = parenthesizeElementTypeMember(type);
node.operator = typeof operatorOrType === "number" ? operatorOrType : SyntaxKind.KeyOfKeyword;
node.type = parenthesizeElementTypeMember(typeof operatorOrType === "number" ? type : operatorOrType);
return node;
}
export function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode) {
return node.type !== type ? updateNode(createTypeOperatorNode(type), node) : node;
return node.type !== type ? updateNode(createTypeOperatorNode(node.operator, type), node) : node;
}
export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) {
@@ -785,10 +787,6 @@ namespace ts {
: node;
}
export function createESSymbolTypeNode() {
return <ESSymbolTypeNode>createSynthesizedNode(SyntaxKind.ESSymbolType);
}
// Binding Patterns
export function createObjectBindingPattern(elements: ReadonlyArray<BindingElement>) {
+8 -19
View File
@@ -2609,19 +2609,6 @@ namespace ts {
return token() === SyntaxKind.DotToken ? undefined : node;
}
function parseSymbolType(): TypeNode | undefined {
const fullStart = scanner.getStartPos();
parseExpected(SyntaxKind.SymbolKeyword);
if (token() === SyntaxKind.DotToken) return undefined;
if (parseOptional(SyntaxKind.OpenParenToken)) {
parseExpected(SyntaxKind.CloseParenToken);
return finishNode(<ESSymbolTypeNode>createNode(SyntaxKind.ESSymbolType, fullStart));
}
else {
return finishNode(<TypeNode>createNode(SyntaxKind.SymbolKeyword, fullStart));
}
}
function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode {
const node = createNode(SyntaxKind.LiteralType) as LiteralTypeNode;
let unaryMinusExpression: PrefixUnaryExpression;
@@ -2655,10 +2642,9 @@ namespace ts {
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.ObjectKeyword:
// If these are followed by a dot, then parse these out as a dotted type reference instead.
return tryParse(parseKeywordAndNoDot) || parseTypeReference();
case SyntaxKind.SymbolKeyword:
return tryParse(parseSymbolType) || parseTypeReference();
// If these are followed by a dot, then parse these out as a dotted type reference instead.
return tryParse(parseKeywordAndNoDot) || parseTypeReference();
case SyntaxKind.AsteriskToken:
return parseJSDocAllType();
case SyntaxKind.QuestionToken:
@@ -2709,6 +2695,7 @@ namespace ts {
case SyntaxKind.NumberKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.UniqueKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NullKeyword:
@@ -2794,7 +2781,7 @@ namespace ts {
return finishNode(postfix);
}
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword) {
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword) {
const node = <TypeOperatorNode>createNode(SyntaxKind.TypeOperator);
parseExpected(operator);
node.operator = operator;
@@ -2803,9 +2790,11 @@ namespace ts {
}
function parseTypeOperatorOrHigher(): TypeNode {
switch (token()) {
const operator = token();
switch (operator) {
case SyntaxKind.KeyOfKeyword:
return parseTypeOperator(SyntaxKind.KeyOfKeyword);
case SyntaxKind.UniqueKeyword:
return parseTypeOperator(operator);
}
return parsePostfixTypeOrHigher();
}
+1
View File
@@ -122,6 +122,7 @@ namespace ts {
"type": SyntaxKind.TypeKeyword,
"typeof": SyntaxKind.TypeOfKeyword,
"undefined": SyntaxKind.UndefinedKeyword,
"unique": SyntaxKind.UniqueKeyword,
"var": SyntaxKind.VarKeyword,
"void": SyntaxKind.VoidKeyword,
"while": SyntaxKind.WhileKeyword,
+4 -9
View File
@@ -199,6 +199,7 @@ namespace ts {
SymbolKeyword,
TypeKeyword,
UndefinedKeyword,
UniqueKeyword,
FromKeyword,
GlobalKeyword,
OfKeyword, // LastKeyword and LastToken
@@ -240,7 +241,6 @@ namespace ts {
IndexedAccessType,
MappedType,
LiteralType,
ESSymbolType,
// Binding patterns
ObjectBindingPattern,
ArrayBindingPattern,
@@ -399,7 +399,7 @@ namespace ts {
FirstFutureReservedWord = ImplementsKeyword,
LastFutureReservedWord = YieldKeyword,
FirstTypeNode = TypePredicate,
LastTypeNode = ESSymbolType,
LastTypeNode = LiteralType,
FirstPunctuation = OpenBraceToken,
LastPunctuation = CaretEqualsToken,
FirstToken = Unknown,
@@ -1030,7 +1030,7 @@ namespace ts {
export interface TypeOperatorNode extends TypeNode {
kind: SyntaxKind.TypeOperator;
operator: SyntaxKind.KeyOfKeyword;
operator: SyntaxKind.KeyOfKeyword | SyntaxKind.UniqueKeyword;
type: TypeNode;
}
@@ -1053,11 +1053,6 @@ namespace ts {
literal: BooleanLiteral | LiteralExpression | PrefixUnaryExpression;
}
// Represents a unique `symbol()` type
export interface ESSymbolTypeNode extends TypeNode {
kind: SyntaxKind.ESSymbolType;
}
export interface StringLiteral extends LiteralExpression {
kind: SyntaxKind.StringLiteral;
/* @internal */ textSourceNode?: Identifier | StringLiteral | NumericLiteral; // Allows a StringLiteral to get its text from another node (used by transforms).
@@ -3209,7 +3204,7 @@ namespace ts {
BooleanLiteral = 1 << 7,
EnumLiteral = 1 << 8, // Always combined with StringLiteral, NumberLiteral, or Union
ESSymbol = 1 << 9, // Type of symbol primitive introduced in ES6
UniqueESSymbol = 1 << 10, // symbol()
UniqueESSymbol = 1 << 10, // unique symbol
Void = 1 << 11,
Undefined = 1 << 12,
Null = 1 << 13,