Skip to content

Commit 9cb38fb

Browse files
committed
Create global Symbol type
1 parent 30892af commit 9cb38fb

29 files changed

+427
-31
lines changed

src/compiler/checker.ts

+58-23
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ module ts {
8484
var globals: SymbolTable = {};
8585

8686
var globalArraySymbol: Symbol;
87+
var globalESSymbolConstructorSymbol: Symbol;
8788

8889
var globalObjectType: ObjectType;
8990
var globalFunctionType: ObjectType;
@@ -93,6 +94,8 @@ module ts {
9394
var globalBooleanType: ObjectType;
9495
var globalRegExpType: ObjectType;
9596
var globalTemplateStringsArrayType: ObjectType;
97+
var globalESSymbolType: ObjectType;
98+
var globalESSymbolConstructorType: ObjectType;
9699

97100
var anyArrayType: Type;
98101

@@ -3005,12 +3008,20 @@ module ts {
30053008
return <ObjectType>type;
30063009
}
30073010

3008-
function getGlobalSymbol(name: string): Symbol {
3009-
return resolveName(undefined, name, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0, name);
3011+
function getGlobalValueSymbol(name: string): Symbol {
3012+
return getGlobalSymbol(name, SymbolFlags.Value, Diagnostics.Cannot_find_global_value_0);
3013+
}
3014+
3015+
function getGlobalTypeSymbol(name: string): Symbol {
3016+
return getGlobalSymbol(name, SymbolFlags.Type, Diagnostics.Cannot_find_global_type_0);
3017+
}
3018+
3019+
function getGlobalSymbol(name: string, meaning: SymbolFlags, diagnostic: DiagnosticMessage): Symbol {
3020+
return resolveName(undefined, name, meaning, diagnostic, name);
30103021
}
30113022

30123023
function getGlobalType(name: string): ObjectType {
3013-
return getTypeOfGlobalSymbol(getGlobalSymbol(name), 0);
3024+
return getTypeOfGlobalSymbol(getGlobalTypeSymbol(name), 0);
30143025
}
30153026

30163027
function createArrayType(elementType: Type): Type {
@@ -5481,7 +5492,7 @@ module ts {
54815492
function isNumericComputedName(name: ComputedPropertyName): boolean {
54825493
// It seems odd to consider an expression of type Any to result in a numeric name,
54835494
// but this behavior is consistent with checkIndexedAccess
5484-
return isTypeOfKind(checkComputedPropertyName(name), TypeFlags.Any | TypeFlags.NumberLike);
5495+
return isTypeOfKind(checkComputedPropertyName(name), TypeFlags.Any | TypeFlags.NumberLike, /*includeESSymbols*/ false);
54855496
}
54865497

54875498
function isNumericLiteralName(name: string) {
@@ -5514,9 +5525,9 @@ module ts {
55145525
if (!links.resolvedType) {
55155526
links.resolvedType = checkExpression(node.expression);
55165527

5517-
// This will allow types number, string, or any. It will also allow enums, the unknown
5528+
// This will allow types number, string, Symbol or any. It will also allow enums, the unknown
55185529
// type, and any union of these types (like string | number).
5519-
if (!isTypeOfKind(links.resolvedType, TypeFlags.Any | TypeFlags.NumberLike | TypeFlags.StringLike)) {
5530+
if (!isTypeOfKind(links.resolvedType, TypeFlags.Any | TypeFlags.NumberLike | TypeFlags.StringLike, /*includeESSymbols*/ true)) {
55205531
error(node, Diagnostics.A_computed_property_name_must_be_of_type_string_number_Symbol_or_any);
55215532
}
55225533
}
@@ -5781,10 +5792,10 @@ module ts {
57815792
}
57825793

57835794
// Check for compatible indexer types.
5784-
if (isTypeOfKind(indexType, TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike)) {
5795+
if (isTypeOfKind(indexType, TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike, /*includeESSymbols*/ true)) {
57855796

57865797
// Try to use a number indexer.
5787-
if (isTypeOfKind(indexType, TypeFlags.Any | TypeFlags.NumberLike)) {
5798+
if (isTypeOfKind(indexType, TypeFlags.Any | TypeFlags.NumberLike, /*includeESSymbols*/ false)) {
57885799
var numberIndexType = getIndexTypeOfType(objectType, IndexKind.Number);
57895800
if (numberIndexType) {
57905801
return numberIndexType;
@@ -6722,7 +6733,7 @@ module ts {
67226733
}
67236734

67246735
function checkArithmeticOperandType(operand: Node, type: Type, diagnostic: DiagnosticMessage): boolean {
6725-
if (!isTypeOfKind(type, TypeFlags.Any | TypeFlags.NumberLike)) {
6736+
if (!isTypeOfKind(type, TypeFlags.Any | TypeFlags.NumberLike, /*includeESSymbols*/ false)) {
67266737
error(operand, diagnostic);
67276738
return false;
67286739
}
@@ -6874,19 +6885,28 @@ module ts {
68746885
}
68756886

68766887
// Return true if type has the given flags, or is a union type composed of types that all have those flags
6877-
function isTypeOfKind(type: Type, kind: TypeFlags): boolean {
6888+
// If include includeESSymbols is true, then check if the type (or union constituents) is an ESSymbol
6889+
// if it does not match the kind. This is necessary because ESSymbol has no corresponding flag.
6890+
function isTypeOfKind(type: Type, kind: TypeFlags, includeESSymbols: boolean): boolean {
68786891
if (type.flags & kind) {
68796892
return true;
68806893
}
68816894
if (type.flags & TypeFlags.Union) {
68826895
var types = (<UnionType>type).types;
68836896
for (var i = 0; i < types.length; i++) {
6884-
if (!(types[i].flags & kind)) {
6885-
return false;
6897+
if (types[i].flags & kind) {
6898+
continue;
6899+
}
6900+
if (includeESSymbols && types[i] === globalESSymbolType) {
6901+
continue;
68866902
}
6903+
return false;
68876904
}
68886905
return true;
68896906
}
6907+
if (includeESSymbols) {
6908+
return type === globalESSymbolType;
6909+
}
68906910
return false;
68916911
}
68926912

@@ -6904,7 +6924,11 @@ module ts {
69046924
// and the right operand to be of type Any or a subtype of the 'Function' interface type.
69056925
// The result is always of the Boolean primitive type.
69066926
// NOTE: do not raise error if leftType is unknown as related error was already reported
6907-
if (isTypeOfKind(leftType, TypeFlags.Primitive)) {
6927+
//
6928+
// The reason for globalESSymbolType !== unknownType is that if the type is unknownType, we don't want to error.
6929+
// If the globalESSymbolType is also unknownType, then by including globalESSymbolType, we will error
6930+
// on unknownType, because transitively, type will be the same as globalESSymbolType.
6931+
if (isTypeOfKind(leftType, TypeFlags.Primitive, /*includeESSymbols*/ globalESSymbolType !== unknownType)) {
69086932
error(node.left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
69096933
}
69106934
// NOTE: do not raise error if right is unknown as related error was already reported
@@ -6919,10 +6943,10 @@ module ts {
69196943
// The in operator requires the left operand to be of type Any, the String primitive type, or the Number primitive type,
69206944
// and the right operand to be of type Any, an object type, or a type parameter type.
69216945
// The result is always of the Boolean primitive type.
6922-
if (!isTypeOfKind(leftType, TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike)) {
6946+
if (!isTypeOfKind(leftType, TypeFlags.Any | TypeFlags.StringLike | TypeFlags.NumberLike, /*includeESSymbols*/ true)) {
69236947
error(node.left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_types_any_string_or_number);
69246948
}
6925-
if (!isTypeOfKind(rightType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) {
6949+
if (!isTypeOfKind(rightType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter, /*includeESSymbols*/ false)) {
69266950
error(node.right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
69276951
}
69286952
return booleanType;
@@ -7083,12 +7107,12 @@ module ts {
70837107
if (rightType.flags & (TypeFlags.Undefined | TypeFlags.Null)) rightType = leftType;
70847108

70857109
var resultType: Type;
7086-
if (isTypeOfKind(leftType, TypeFlags.NumberLike) && isTypeOfKind(rightType, TypeFlags.NumberLike)) {
7110+
if (isTypeOfKind(leftType, TypeFlags.NumberLike, /*includeESSymbols*/ false) && isTypeOfKind(rightType, TypeFlags.NumberLike, /*includeESSymbols*/ false)) {
70877111
// Operands of an enum type are treated as having the primitive type Number.
70887112
// If both operands are of the Number primitive type, the result is of the Number primitive type.
70897113
resultType = numberType;
70907114
}
7091-
else if (isTypeOfKind(leftType, TypeFlags.StringLike) || isTypeOfKind(rightType, TypeFlags.StringLike)) {
7115+
else if (isTypeOfKind(leftType, TypeFlags.StringLike, /*includeESSymbols*/ false) || isTypeOfKind(rightType, TypeFlags.StringLike, /*includeESSymbols*/ false)) {
70927116
// If one or both operands are of the String primitive type, the result is of the String primitive type.
70937117
resultType = stringType;
70947118
}
@@ -8454,7 +8478,7 @@ module ts {
84548478
// and Expr must be an expression of type Any, an object type, or a type parameter type.
84558479
var varExpr = <Expression>node.initializer;
84568480
var exprType = checkExpression(varExpr);
8457-
if (exprType !== anyType && exprType !== stringType) {
8481+
if (!isTypeOfKind(exprType, TypeFlags.Any | TypeFlags.StringLike, /*includeESSymbols*/ true)) {
84588482
error(varExpr, Diagnostics.The_left_hand_side_of_a_for_in_statement_must_be_of_type_string_or_any);
84598483
}
84608484
else {
@@ -8466,7 +8490,7 @@ module ts {
84668490
var exprType = checkExpression(node.expression);
84678491
// unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved
84688492
// in this case error about missing name is already reported - do not report extra one
8469-
if (!isTypeOfKind(exprType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) {
8493+
if (!isTypeOfKind(exprType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter, /*includeESSymbols*/ false)) {
84708494
error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter);
84718495
}
84728496

@@ -10251,19 +10275,30 @@ module ts {
1025110275
getSymbolLinks(unknownSymbol).type = unknownType;
1025210276
globals[undefinedSymbol.name] = undefinedSymbol;
1025310277
// Initialize special types
10254-
globalArraySymbol = getGlobalSymbol("Array");
10278+
globalArraySymbol = getGlobalTypeSymbol("Array");
1025510279
globalArrayType = getTypeOfGlobalSymbol(globalArraySymbol, 1);
1025610280
globalObjectType = getGlobalType("Object");
1025710281
globalFunctionType = getGlobalType("Function");
1025810282
globalStringType = getGlobalType("String");
1025910283
globalNumberType = getGlobalType("Number");
1026010284
globalBooleanType = getGlobalType("Boolean");
1026110285
globalRegExpType = getGlobalType("RegExp");
10286+
1026210287
// If we're in ES6 mode, load the TemplateStringsArray.
1026310288
// Otherwise, default to 'unknown' for the purposes of type checking in LS scenarios.
10264-
globalTemplateStringsArrayType = languageVersion >= ScriptTarget.ES6
10265-
? getGlobalType("TemplateStringsArray")
10266-
: unknownType;
10289+
if (languageVersion >= ScriptTarget.ES6) {
10290+
globalTemplateStringsArrayType = getGlobalType("TemplateStringsArray");
10291+
globalESSymbolType = getGlobalType("Symbol");
10292+
globalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol");
10293+
globalESSymbolConstructorType = getTypeOfGlobalSymbol(globalESSymbolConstructorSymbol, /*arity*/ 0);
10294+
}
10295+
else {
10296+
globalTemplateStringsArrayType = unknownType;
10297+
globalESSymbolType = unknownType;
10298+
globalESSymbolConstructorSymbol = unknownSymbol;
10299+
globalESSymbolConstructorType = unknownType;
10300+
}
10301+
1026710302
anyArrayType = createArrayType(anyType);
1026810303
}
1026910304

src/compiler/diagnosticInformationMap.generated.ts

+1
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ module ts {
304304
this_cannot_be_referenced_in_a_computed_property_name: { code: 2465, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in a computed property name." },
305305
super_cannot_be_referenced_in_a_computed_property_name: { code: 2466, category: DiagnosticCategory.Error, key: "'super' cannot be referenced in a computed property name." },
306306
A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type: { code: 2466, category: DiagnosticCategory.Error, key: "A computed property name cannot reference a type parameter from its containing type." },
307+
Cannot_find_global_value_0: { code: 2468, category: DiagnosticCategory.Error, key: "Cannot find global value '{0}'." },
307308
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
308309
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
309310
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,10 @@
12091209
"category": "Error",
12101210
"code": 2466
12111211
},
1212+
"Cannot find global value '{0}'.": {
1213+
"category": "Error",
1214+
"code": 2468
1215+
},
12121216

12131217
"Import declaration '{0}' is using private name '{1}'.": {
12141218
"category": "Error",

tests/baselines/reference/parserForStatement3.errors.txt

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement3.ts(1,5): error TS2304: Cannot find name 'd'.
2-
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement3.ts(1,5): error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'.
32
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement3.ts(1,10): error TS2304: Cannot find name '_'.
43
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement3.ts(1,15): error TS2304: Cannot find name 'a'.
54
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement3.ts(1,18): error TS2304: Cannot find name '_'.
65
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement3.ts(1,23): error TS2304: Cannot find name 'a'.
76
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement3.ts(1,30): error TS2304: Cannot find name 'b'.
87

98

10-
==== tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement3.ts (7 errors) ====
9+
==== tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement3.ts (6 errors) ====
1110
for(d in _.jh[a]=_.jh[a]||[],b);
1211
~
1312
!!! error TS2304: Cannot find name 'd'.
14-
~
15-
!!! error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'.
1613
~
1714
!!! error TS2304: Cannot find name '_'.
1815
~
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement6.ts(1,6): error TS2304: Cannot find name 'foo'.
2-
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement6.ts(1,6): error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'.
2+
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement6.ts(1,6): error TS2406: Invalid left-hand side in 'for...in' statement.
33
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement6.ts(1,15): error TS2304: Cannot find name 'b'.
44

55

@@ -8,7 +8,7 @@ tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement6.ts(1,1
88
~~~
99
!!! error TS2304: Cannot find name 'foo'.
1010
~~~~~
11-
!!! error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'.
11+
!!! error TS2406: Invalid left-hand side in 'for...in' statement.
1212
~
1313
!!! error TS2304: Cannot find name 'b'.
1414
}

tests/baselines/reference/parserForStatement7.errors.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement7.ts(1,6): error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'.
1+
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement7.ts(1,6): error TS2406: Invalid left-hand side in 'for...in' statement.
22
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement7.ts(1,10): error TS2304: Cannot find name 'foo'.
33
tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement7.ts(1,19): error TS2304: Cannot find name 'b'.
44

55

66
==== tests/cases/conformance/parser/ecmascript5/Statements/parserForStatement7.ts (3 errors) ====
77
for (new foo() in b) {
88
~~~~~~~~~
9-
!!! error TS2405: The left-hand side of a 'for...in' statement must be of type 'string' or 'any'.
9+
!!! error TS2406: Invalid left-hand side in 'for...in' statement.
1010
~~~
1111
!!! error TS2304: Cannot find name 'foo'.
1212
~
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [symbolProperty1.ts]
2+
var s: Symbol;
3+
var x = {
4+
[s]: 0,
5+
[s]() { },
6+
get [s]() {
7+
return 0;
8+
}
9+
}
10+
11+
//// [symbolProperty1.js]
12+
var s;
13+
var x = {
14+
[s]: 0,
15+
[s]() {
16+
},
17+
get [s]() {
18+
return 0;
19+
}
20+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/conformance/es6/Symbols/symbolProperty1.ts ===
2+
var s: Symbol;
3+
>s : Symbol
4+
>Symbol : Symbol
5+
6+
var x = {
7+
>x : {}
8+
>{ [s]: 0, [s]() { }, get [s]() { return 0; }} : {}
9+
10+
[s]: 0,
11+
>s : Symbol
12+
13+
[s]() { },
14+
>s : Symbol
15+
16+
get [s]() {
17+
>s : Symbol
18+
19+
return 0;
20+
}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//// [symbolProperty2.ts]
2+
var s = Symbol();
3+
var x = {
4+
[s]: 0,
5+
[s]() { },
6+
get [s]() {
7+
return 0;
8+
}
9+
}
10+
11+
//// [symbolProperty2.js]
12+
var s = Symbol();
13+
var x = {
14+
[s]: 0,
15+
[s]() {
16+
},
17+
get [s]() {
18+
return 0;
19+
}
20+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== tests/cases/conformance/es6/Symbols/symbolProperty2.ts ===
2+
var s = Symbol();
3+
>s : Symbol
4+
>Symbol() : Symbol
5+
>Symbol : SymbolConstructor
6+
7+
var x = {
8+
>x : {}
9+
>{ [s]: 0, [s]() { }, get [s]() { return 0; }} : {}
10+
11+
[s]: 0,
12+
>s : Symbol
13+
14+
[s]() { },
15+
>s : Symbol
16+
17+
get [s]() {
18+
>s : Symbol
19+
20+
return 0;
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
tests/cases/conformance/es6/Symbols/symbolProperty3.ts(3,5): error TS2464: A computed property name must be of type 'string', 'number', 'Symbol', or 'any'.
2+
tests/cases/conformance/es6/Symbols/symbolProperty3.ts(4,5): error TS2464: A computed property name must be of type 'string', 'number', 'Symbol', or 'any'.
3+
tests/cases/conformance/es6/Symbols/symbolProperty3.ts(5,9): error TS2464: A computed property name must be of type 'string', 'number', 'Symbol', or 'any'.
4+
5+
6+
==== tests/cases/conformance/es6/Symbols/symbolProperty3.ts (3 errors) ====
7+
var s = Symbol;
8+
var x = {
9+
[s]: 0,
10+
~~~
11+
!!! error TS2464: A computed property name must be of type 'string', 'number', 'Symbol', or 'any'.
12+
[s]() { },
13+
~~~
14+
!!! error TS2464: A computed property name must be of type 'string', 'number', 'Symbol', or 'any'.
15+
get [s]() {
16+
~~~
17+
!!! error TS2464: A computed property name must be of type 'string', 'number', 'Symbol', or 'any'.
18+
return 0;
19+
}
20+
}

0 commit comments

Comments
 (0)