Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 87d10eb

Browse filesBrowse files
authored
Eliminate well known symbols as a concept in the checker and rely on unique symbols (microsoft#42543)
* Eliminate well-known symbols in the checker: 2021 edition * Actually update the lib text to say unique symbol, too (this is unneeded with compat code in place, but this makes goto-def make more sense) * Add test showing mismatched symbol constructor type interop * Add more test cases for some other related issues this fixes * Revert computed name change * Style comments
1 parent 5a1d308 commit 87d10eb
Copy full SHA for 87d10eb

235 files changed

+1,230-1,022Lines changed: 1230 additions & 1022 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎src/compiler/binder.ts‎

Copy file name to clipboardExpand all lines: src/compiler/binder.ts
+3-6Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -344,12 +344,9 @@ namespace ts {
344344
if (isSignedNumericLiteral(nameExpression)) {
345345
return tokenToString(nameExpression.operator) + nameExpression.operand.text as __String;
346346
}
347-
348-
Debug.assert(isWellKnownSymbolSyntactically(nameExpression));
349-
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>nameExpression).name));
350-
}
351-
if (isWellKnownSymbolSyntactically(name)) {
352-
return getPropertyNameForKnownSymbolName(idText(name.name));
347+
else {
348+
Debug.fail("Only computed properties with literal names have declaration names");
349+
}
353350
}
354351
if (isPrivateIdentifier(name)) {
355352
// containingClass exists because private names only allowed inside classes
Collapse file

‎src/compiler/checker.ts‎

Copy file name to clipboardExpand all lines: src/compiler/checker.ts
+49-59Lines changed: 49 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,7 @@ namespace ts {
898898
// This allows users to just specify library files they want to used through --lib
899899
// and they will not get an error from not having unrelated library files
900900
let deferredGlobalESSymbolConstructorSymbol: Symbol | undefined;
901+
let deferredGlobalESSymbolConstructorTypeSymbol: Symbol | undefined;
901902
let deferredGlobalESSymbolType: ObjectType;
902903
let deferredGlobalTypedPropertyDescriptorType: GenericType;
903904
let deferredGlobalPromiseType: GenericType;
@@ -3677,11 +3678,30 @@ namespace ts {
36773678
const additionalContainers = mapDefined(container.declarations, fileSymbolIfFileSymbolExportEqualsContainer);
36783679
const reexportContainers = enclosingDeclaration && getAlternativeContainingModules(symbol, enclosingDeclaration);
36793680
const objectLiteralContainer = getVariableDeclarationOfObjectLiteral(container, meaning);
3680-
if (enclosingDeclaration && getAccessibleSymbolChain(container, enclosingDeclaration, SymbolFlags.Namespace, /*externalOnly*/ false)) {
3681+
if (
3682+
enclosingDeclaration &&
3683+
container.flags & getQualifiedLeftMeaning(meaning) &&
3684+
getAccessibleSymbolChain(container, enclosingDeclaration, SymbolFlags.Namespace, /*externalOnly*/ false)
3685+
) {
36813686
return append(concatenate(concatenate([container], additionalContainers), reexportContainers), objectLiteralContainer); // This order expresses a preference for the real container if it is in scope
36823687
}
3683-
const res = append(append(additionalContainers, container), objectLiteralContainer);
3684-
return concatenate(res, reexportContainers);
3688+
// we potentially have a symbol which is a member of the instance side of something - look for a variable in scope with the container's type
3689+
// which may be acting like a namespace (eg, `Symbol` acts like a namespace when looking up `Symbol.toStringTag`)
3690+
const firstVariableMatch = !(container.flags & getQualifiedLeftMeaning(meaning))
3691+
&& container.flags & SymbolFlags.Type
3692+
&& getDeclaredTypeOfSymbol(container).flags & TypeFlags.Object
3693+
&& meaning === SymbolFlags.Value
3694+
? forEachSymbolTableInScope(enclosingDeclaration, t => {
3695+
return forEachEntry(t, s => {
3696+
if (s.flags & getQualifiedLeftMeaning(meaning) && getTypeOfSymbol(s) === getDeclaredTypeOfSymbol(container)) {
3697+
return s;
3698+
}
3699+
});
3700+
}) : undefined;
3701+
let res = firstVariableMatch ? [firstVariableMatch, ...additionalContainers, container] : [...additionalContainers, container];
3702+
res = append(res, objectLiteralContainer);
3703+
res = addRange(res, reexportContainers);
3704+
return res;
36853705
}
36863706
const candidates = mapDefined(symbol.declarations, d => {
36873707
if (!isAmbientModule(d) && d.parent && hasNonGlobalAugmentationExternalModuleSymbol(d.parent)) {
@@ -5107,8 +5127,9 @@ namespace ts {
51075127
}
51085128
}
51095129
}
5110-
context.enclosingDeclaration = saveEnclosingDeclaration;
5130+
context.enclosingDeclaration = propertySymbol.valueDeclaration || propertySymbol.declarations?.[0] || saveEnclosingDeclaration;
51115131
const propertyName = getPropertyNameNodeForSymbol(propertySymbol, context);
5132+
context.enclosingDeclaration = saveEnclosingDeclaration;
51125133
context.approximateLength += (symbolName(propertySymbol).length + 1);
51135134
const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined;
51145135
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length && !isReadonlySymbol(propertySymbol)) {
@@ -5852,9 +5873,6 @@ namespace ts {
58525873
if (fromNameType) {
58535874
return fromNameType;
58545875
}
5855-
if (isKnownSymbol(symbol)) {
5856-
return factory.createComputedPropertyName(factory.createPropertyAccessExpression(factory.createIdentifier("Symbol"), (symbol.escapedName as string).substr(3)));
5857-
}
58585876
const rawName = unescapeLeadingUnderscores(symbol.escapedName);
58595877
const stringNamed = !!length(symbol.declarations) && every(symbol.declarations, isStringNamed);
58605878
return createPropertyNameNodeForIdentifierOrLiteral(rawName, stringNamed, singleQuote);
@@ -8707,8 +8725,18 @@ namespace ts {
87078725
return widenTypeForVariableLikeDeclaration(getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true), declaration, reportErrors);
87088726
}
87098727

8728+
function isGlobalSymbolConstructor(node: Node) {
8729+
const symbol = getSymbolOfNode(node);
8730+
const globalSymbol = getGlobalESSymbolConstructorTypeSymbol(/*reportErrors*/ false);
8731+
return globalSymbol && symbol && symbol === globalSymbol;
8732+
}
8733+
87108734
function widenTypeForVariableLikeDeclaration(type: Type | undefined, declaration: any, reportErrors?: boolean) {
87118735
if (type) {
8736+
// TODO: If back compat with pre-3.0/4.0 libs isn't required, remove the following SymbolConstructor special case transforming `symbol` into `unique symbol`
8737+
if (type.flags & TypeFlags.ESSymbol && isGlobalSymbolConstructor(declaration.parent)) {
8738+
type = getESSymbolLikeTypeForNode(declaration);
8739+
}
87128740
if (reportErrors) {
87138741
reportErrorsFromWidening(declaration, type);
87148742
}
@@ -12859,6 +12887,10 @@ namespace ts {
1285912887
return deferredGlobalESSymbolConstructorSymbol || (deferredGlobalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol" as __String, reportErrors));
1286012888
}
1286112889

12890+
function getGlobalESSymbolConstructorTypeSymbol(reportErrors: boolean) {
12891+
return deferredGlobalESSymbolConstructorTypeSymbol || (deferredGlobalESSymbolConstructorTypeSymbol = getGlobalTypeSymbol("SymbolConstructor" as __String, reportErrors));
12892+
}
12893+
1286212894
function getGlobalESSymbolType(reportErrors: boolean) {
1286312895
return deferredGlobalESSymbolType || (deferredGlobalESSymbolType = getGlobalType("Symbol" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType;
1286412896
}
@@ -13941,13 +13973,13 @@ namespace ts {
1394113973
function getLiteralTypeFromProperty(prop: Symbol, include: TypeFlags) {
1394213974
if (!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) {
1394313975
let type = getSymbolLinks(getLateBoundSymbol(prop)).nameType;
13944-
if (!type && !isKnownSymbol(prop)) {
13976+
if (!type) {
1394513977
if (prop.escapedName === InternalSymbolName.Default) {
1394613978
type = getLiteralType("default");
1394713979
}
1394813980
else {
1394913981
const name = prop.valueDeclaration && getNameOfDeclaration(prop.valueDeclaration) as PropertyName;
13950-
type = name && getLiteralTypeFromPropertyName(name) || getLiteralType(symbolName(prop));
13982+
type = name && getLiteralTypeFromPropertyName(name) || (!isKnownSymbol(prop) ? getLiteralType(symbolName(prop)) : undefined);
1395113983
}
1395213984
}
1395313985
if (type && type.flags & include) {
@@ -14174,11 +14206,8 @@ namespace ts {
1417414206
}
1417514207

1417614208
function getPropertyNameFromIndex(indexType: Type, accessNode: StringLiteral | Identifier | PrivateIdentifier | ObjectBindingPattern | ArrayBindingPattern | ComputedPropertyName | NumericLiteral | IndexedAccessTypeNode | ElementAccessExpression | SyntheticExpression | undefined) {
14177-
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
1417814209
return isTypeUsableAsPropertyName(indexType) ?
1417914210
getPropertyNameFromType(indexType) :
14180-
accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ?
14181-
getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>accessExpression.argumentExpression).name)) :
1418214211
accessNode && isPropertyName(accessNode) ?
1418314212
// late bound names are handled in the first branch, so here we only need to handle normal names
1418414213
getPropertyNameForPropertyNameNode(accessNode) :
@@ -25279,9 +25308,6 @@ namespace ts {
2527925308
!isTypeAssignableTo(links.resolvedType, stringNumberSymbolType)) {
2528025309
error(node, Diagnostics.A_computed_property_name_must_be_of_type_string_number_symbol_or_any);
2528125310
}
25282-
else {
25283-
checkThatExpressionIsProperSymbolReference(node.expression, links.resolvedType, /*reportError*/ true);
25284-
}
2528525311
}
2528625312

2528725313
return links.resolvedType;
@@ -25342,15 +25368,15 @@ namespace ts {
2534225368
// As otherwise they may not be checked until exports for the type at this position are retrieved,
2534325369
// which may never occur.
2534425370
for (const elem of node.properties) {
25345-
if (elem.name && isComputedPropertyName(elem.name) && !isWellKnownSymbolSyntactically(elem.name)) {
25371+
if (elem.name && isComputedPropertyName(elem.name)) {
2534625372
checkComputedPropertyName(elem.name);
2534725373
}
2534825374
}
2534925375

2535025376
let offset = 0;
2535125377
for (const memberDecl of node.properties) {
2535225378
let member = getSymbolOfNode(memberDecl);
25353-
const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName && !isWellKnownSymbolSyntactically(memberDecl.name.expression) ?
25379+
const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName ?
2535425380
checkComputedPropertyName(memberDecl.name) : undefined;
2535525381
if (memberDecl.kind === SyntaxKind.PropertyAssignment ||
2535625382
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ||
@@ -27006,48 +27032,6 @@ namespace ts {
2700627032
return checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, indexedAccessType.symbol, indexedAccessType, indexExpression), node);
2700727033
}
2700827034

27009-
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
27010-
if (expressionType === errorType) {
27011-
// There is already an error, so no need to report one.
27012-
return false;
27013-
}
27014-
27015-
if (!isWellKnownSymbolSyntactically(expression)) {
27016-
return false;
27017-
}
27018-
27019-
// Make sure the property type is the primitive symbol type
27020-
if ((expressionType.flags & TypeFlags.ESSymbolLike) === 0) {
27021-
if (reportError) {
27022-
error(expression, Diagnostics.A_computed_property_name_of_the_form_0_must_be_of_type_symbol, getTextOfNode(expression));
27023-
}
27024-
return false;
27025-
}
27026-
27027-
// The name is Symbol.<someName>, so make sure Symbol actually resolves to the
27028-
// global Symbol object
27029-
const leftHandSide = <Identifier>(<PropertyAccessExpression>expression).expression;
27030-
const leftHandSideSymbol = getResolvedSymbol(leftHandSide);
27031-
if (!leftHandSideSymbol) {
27032-
return false;
27033-
}
27034-
27035-
const globalESSymbol = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ true);
27036-
if (!globalESSymbol) {
27037-
// Already errored when we tried to look up the symbol
27038-
return false;
27039-
}
27040-
27041-
if (leftHandSideSymbol !== globalESSymbol) {
27042-
if (reportError) {
27043-
error(leftHandSide, Diagnostics.Symbol_reference_does_not_refer_to_the_global_Symbol_constructor_object);
27044-
}
27045-
return false;
27046-
}
27047-
27048-
return true;
27049-
}
27050-
2705127035
function callLikeExpressionMayHaveTypeArguments(node: CallLikeExpression): node is CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement {
2705227036
return isCallOrNewExpression(node) || isTaggedTemplateExpression(node) || isJsxOpeningLikeElement(node);
2705327037
}
@@ -35355,6 +35339,12 @@ namespace ts {
3535535339
}
3535635340
}
3535735341

35342+
function getPropertyNameForKnownSymbolName(symbolName: string): __String {
35343+
const ctorType = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ false);
35344+
const uniqueType = ctorType && getTypeOfPropertyOfType(getTypeOfSymbol(ctorType), escapeLeadingUnderscores(symbolName));
35345+
return uniqueType && isTypeUsableAsPropertyName(uniqueType) ? getPropertyNameFromType(uniqueType) : `__@${symbolName}` as __String;
35346+
}
35347+
3535835348
/**
3535935349
* Gets the *yield*, *return*, and *next* types of an `Iterable`-like or `AsyncIterable`-like
3536035350
* type from its members.
Collapse file

‎src/compiler/transformers/utilities.ts‎

Copy file name to clipboardExpand all lines: src/compiler/transformers/utilities.ts
+1-2Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,7 @@ namespace ts {
269269
* any such locations
270270
*/
271271
export function isSimpleInlineableExpression(expression: Expression) {
272-
return !isIdentifier(expression) && isSimpleCopiableExpression(expression) ||
273-
isWellKnownSymbolSyntactically(expression);
272+
return !isIdentifier(expression) && isSimpleCopiableExpression(expression);
274273
}
275274

276275
export function isCompoundAssignment(kind: BinaryOperator): kind is CompoundAssignmentOperator {
Collapse file

‎src/compiler/types.ts‎

Copy file name to clipboardExpand all lines: src/compiler/types.ts
+1-7Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2307,12 +2307,6 @@ namespace ts {
23072307
| CallChainRoot
23082308
;
23092309

2310-
/** @internal */
2311-
export interface WellKnownSymbolExpression extends PropertyAccessExpression {
2312-
readonly expression: Identifier & { readonly escapedText: __String & "Symbol" };
2313-
readonly name: Identifier;
2314-
}
2315-
23162310
/** @internal */
23172311
export type BindableObjectDefinePropertyCall = CallExpression & {
23182312
readonly arguments: readonly [BindableStaticNameExpression, StringLiteralLike | NumericLiteral, ObjectLiteralExpression] & Readonly<TextRange>;
@@ -2326,7 +2320,7 @@ namespace ts {
23262320

23272321
/** @internal */
23282322
export type LiteralLikeElementAccessExpression = ElementAccessExpression & Declaration & {
2329-
readonly argumentExpression: StringLiteralLike | NumericLiteral | WellKnownSymbolExpression;
2323+
readonly argumentExpression: StringLiteralLike | NumericLiteral;
23302324
};
23312325

23322326
/** @internal */
Collapse file

‎src/compiler/utilities.ts‎

Copy file name to clipboardExpand all lines: src/compiler/utilities.ts
+3-28Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2241,9 +2241,7 @@ namespace ts {
22412241

22422242
/** x[0] OR x['a'] OR x[Symbol.y] */
22432243
export function isLiteralLikeElementAccess(node: Node): node is LiteralLikeElementAccessExpression {
2244-
return isElementAccessExpression(node) && (
2245-
isStringOrNumericLiteralLike(node.argumentExpression) ||
2246-
isWellKnownSymbolSyntactically(node.argumentExpression));
2244+
return isElementAccessExpression(node) && isStringOrNumericLiteralLike(node.argumentExpression);
22472245
}
22482246

22492247
/** Any series of property and element accesses. */
@@ -2328,9 +2326,6 @@ namespace ts {
23282326
return escapeLeadingUnderscores(name.text);
23292327
}
23302328
}
2331-
if (isElementAccessExpression(node) && isWellKnownSymbolSyntactically(node.argumentExpression)) {
2332-
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>node.argumentExpression).name));
2333-
}
23342329
return undefined;
23352330
}
23362331

@@ -3139,9 +3134,6 @@ namespace ts {
31393134
* 3. The computed name is *not* expressed as a NumericLiteral.
31403135
* 4. The computed name is *not* expressed as a PlusToken or MinusToken
31413136
* immediately followed by a NumericLiteral.
3142-
* 5. The computed name is *not* expressed as `Symbol.<name>`, where `<name>`
3143-
* is a property of the Symbol constructor that denotes a built-in
3144-
* Symbol.
31453137
*/
31463138
export function hasDynamicName(declaration: Declaration): declaration is DynamicNamedDeclaration | DynamicNamedBinaryExpression {
31473139
const name = getNameOfDeclaration(declaration);
@@ -3154,17 +3146,7 @@ namespace ts {
31543146
}
31553147
const expr = isElementAccessExpression(name) ? skipParentheses(name.argumentExpression) : name.expression;
31563148
return !isStringOrNumericLiteralLike(expr) &&
3157-
!isSignedNumericLiteral(expr) &&
3158-
!isWellKnownSymbolSyntactically(expr);
3159-
}
3160-
3161-
/**
3162-
* Checks if the expression is of the form:
3163-
* Symbol.name
3164-
* where Symbol is literally the word "Symbol", and name is any identifierName
3165-
*/
3166-
export function isWellKnownSymbolSyntactically(node: Node): node is WellKnownSymbolExpression {
3167-
return isPropertyAccessExpression(node) && isESSymbolIdentifier(node.expression);
3149+
!isSignedNumericLiteral(expr);
31683150
}
31693151

31703152
export function getPropertyNameForPropertyNameNode(name: PropertyName): __String | undefined {
@@ -3177,10 +3159,7 @@ namespace ts {
31773159
return escapeLeadingUnderscores(name.text);
31783160
case SyntaxKind.ComputedPropertyName:
31793161
const nameExpression = name.expression;
3180-
if (isWellKnownSymbolSyntactically(nameExpression)) {
3181-
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>nameExpression).name));
3182-
}
3183-
else if (isStringOrNumericLiteralLike(nameExpression)) {
3162+
if (isStringOrNumericLiteralLike(nameExpression)) {
31843163
return escapeLeadingUnderscores(nameExpression.text);
31853164
}
31863165
else if (isSignedNumericLiteral(nameExpression)) {
@@ -3218,10 +3197,6 @@ namespace ts {
32183197
return `__@${getSymbolId(symbol)}@${symbol.escapedName}` as __String;
32193198
}
32203199

3221-
export function getPropertyNameForKnownSymbolName(symbolName: string): __String {
3222-
return "__@" + symbolName as __String;
3223-
}
3224-
32253200
export function getSymbolNameForPrivateIdentifier(containingClassSymbol: Symbol, description: __String): __String {
32263201
return `__#${getSymbolId(containingClassSymbol)}@${description}` as __String;
32273202
}
Collapse file

‎src/lib/es2015.iterable.d.ts‎

Copy file name to clipboardExpand all lines: src/lib/es2015.iterable.d.ts
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ interface SymbolConstructor {
55
* A method that returns the default iterator for an object. Called by the semantics of the
66
* for-of statement.
77
*/
8-
readonly iterator: symbol;
8+
readonly iterator: unique symbol;
99
}
1010

1111
interface IteratorYieldResult<TYield> {

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.