Skip to content

Commit 31dc466

Browse files
committed
Eliminate well-known symbols in the checker: 2021 edition
1 parent 5a21291 commit 31dc466

File tree

267 files changed

+1009
-1122
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

267 files changed

+1009
-1122
lines changed

src/compiler/binder.ts

Lines 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

src/compiler/checker.ts

Lines changed: 47 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,25 @@ 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 (enclosingDeclaration && container.flags & getQualifiedLeftMeaning(meaning) && getAccessibleSymbolChain(container, enclosingDeclaration, SymbolFlags.Namespace, /*externalOnly*/ false)) {
36813682
return append(concatenate(concatenate([container], additionalContainers), reexportContainers), objectLiteralContainer); // This order expresses a preference for the real container if it is in scope
36823683
}
3684+
// we potentially a symbol which is a member of the instance side of something - look for a variable in scope with the container's type
3685+
// which may be acting like a namespace
3686+
const firstVariableMatch = !(container.flags & getQualifiedLeftMeaning(meaning))
3687+
&& container.flags & SymbolFlags.Type
3688+
&& getDeclaredTypeOfSymbol(container).flags & TypeFlags.Object
3689+
&& meaning === SymbolFlags.Value
3690+
? forEachSymbolTableInScope(enclosingDeclaration, t => {
3691+
return forEachEntry(t, s => {
3692+
if (s.flags & getQualifiedLeftMeaning(meaning) && getTypeOfSymbol(s) === getDeclaredTypeOfSymbol(container)) {
3693+
return s;
3694+
}
3695+
});
3696+
}) : undefined;
36833697
const res = append(append(additionalContainers, container), objectLiteralContainer);
3684-
return concatenate(res, reexportContainers);
3698+
const resWithReexports = concatenate(res, reexportContainers);
3699+
return firstVariableMatch ? [firstVariableMatch, ...resWithReexports] : resWithReexports;
36853700
}
36863701
const candidates = mapDefined(symbol.declarations, d => {
36873702
if (!isAmbientModule(d) && d.parent && hasNonGlobalAugmentationExternalModuleSymbol(d.parent)) {
@@ -5104,8 +5119,9 @@ namespace ts {
51045119
}
51055120
}
51065121
}
5107-
context.enclosingDeclaration = saveEnclosingDeclaration;
5122+
context.enclosingDeclaration = propertySymbol.valueDeclaration || propertySymbol.declarations?.[0] || saveEnclosingDeclaration;
51085123
const propertyName = getPropertyNameNodeForSymbol(propertySymbol, context);
5124+
context.enclosingDeclaration = saveEnclosingDeclaration;
51095125
context.approximateLength += (symbolName(propertySymbol).length + 1);
51105126
const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? factory.createToken(SyntaxKind.QuestionToken) : undefined;
51115127
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length && !isReadonlySymbol(propertySymbol)) {
@@ -5849,9 +5865,6 @@ namespace ts {
58495865
if (fromNameType) {
58505866
return fromNameType;
58515867
}
5852-
if (isKnownSymbol(symbol)) {
5853-
return factory.createComputedPropertyName(factory.createPropertyAccessExpression(factory.createIdentifier("Symbol"), (symbol.escapedName as string).substr(3)));
5854-
}
58555868
const rawName = unescapeLeadingUnderscores(symbol.escapedName);
58565869
const stringNamed = !!length(symbol.declarations) && every(symbol.declarations, isStringNamed);
58575870
return createPropertyNameNodeForIdentifierOrLiteral(rawName, stringNamed, singleQuote);
@@ -8704,8 +8717,18 @@ namespace ts {
87048717
return widenTypeForVariableLikeDeclaration(getTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true), declaration, reportErrors);
87058718
}
87068719

8720+
function isGlobalSymbolConstructor(node: Node) {
8721+
const symbol = getSymbolOfNode(node);
8722+
const globalSymbol = getGlobalESSymbolConstructorTypeSymbol(/*reportErrors*/ false);
8723+
return globalSymbol && symbol && symbol === globalSymbol;
8724+
}
8725+
87078726
function widenTypeForVariableLikeDeclaration(type: Type | undefined, declaration: any, reportErrors?: boolean) {
87088727
if (type) {
8728+
// TODO: Remove the following SymbolConstructor special case when back compat with pre-3.0 libs isn't required
8729+
if (type.flags & TypeFlags.ESSymbol && isGlobalSymbolConstructor(declaration.parent)) {
8730+
type = getESSymbolLikeTypeForNode(declaration);
8731+
}
87098732
if (reportErrors) {
87108733
reportErrorsFromWidening(declaration, type);
87118734
}
@@ -12835,6 +12858,10 @@ namespace ts {
1283512858
return deferredGlobalESSymbolConstructorSymbol || (deferredGlobalESSymbolConstructorSymbol = getGlobalValueSymbol("Symbol" as __String, reportErrors));
1283612859
}
1283712860

12861+
function getGlobalESSymbolConstructorTypeSymbol(reportErrors: boolean) {
12862+
return deferredGlobalESSymbolConstructorTypeSymbol || (deferredGlobalESSymbolConstructorTypeSymbol = getGlobalTypeSymbol("SymbolConstructor" as __String, reportErrors));
12863+
}
12864+
1283812865
function getGlobalESSymbolType(reportErrors: boolean) {
1283912866
return deferredGlobalESSymbolType || (deferredGlobalESSymbolType = getGlobalType("Symbol" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType;
1284012867
}
@@ -13919,13 +13946,13 @@ namespace ts {
1391913946
function getLiteralTypeFromProperty(prop: Symbol, include: TypeFlags) {
1392013947
if (!(getDeclarationModifierFlagsFromSymbol(prop) & ModifierFlags.NonPublicAccessibilityModifier)) {
1392113948
let type = getSymbolLinks(getLateBoundSymbol(prop)).nameType;
13922-
if (!type && !isKnownSymbol(prop)) {
13949+
if (!type) {
1392313950
if (prop.escapedName === InternalSymbolName.Default) {
1392413951
type = getLiteralType("default");
1392513952
}
1392613953
else {
1392713954
const name = prop.valueDeclaration && getNameOfDeclaration(prop.valueDeclaration) as PropertyName;
13928-
type = name && getLiteralTypeFromPropertyName(name) || getLiteralType(symbolName(prop));
13955+
type = name && getLiteralTypeFromPropertyName(name) || (!isKnownSymbol(prop) ? getLiteralType(symbolName(prop)) : undefined);
1392913956
}
1393013957
}
1393113958
if (type && type.flags & include) {
@@ -14153,11 +14180,8 @@ namespace ts {
1415314180
}
1415414181

1415514182
function getPropertyNameFromIndex(indexType: Type, accessNode: StringLiteral | Identifier | PrivateIdentifier | ObjectBindingPattern | ArrayBindingPattern | ComputedPropertyName | NumericLiteral | IndexedAccessTypeNode | ElementAccessExpression | SyntheticExpression | undefined) {
14156-
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
1415714183
return isTypeUsableAsPropertyName(indexType) ?
1415814184
getPropertyNameFromType(indexType) :
14159-
accessExpression && checkThatExpressionIsProperSymbolReference(accessExpression.argumentExpression, indexType, /*reportError*/ false) ?
14160-
getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>accessExpression.argumentExpression).name)) :
1416114185
accessNode && isPropertyName(accessNode) ?
1416214186
// late bound names are handled in the first branch, so here we only need to handle normal names
1416314187
getPropertyNameForPropertyNameNode(accessNode) :
@@ -25151,9 +25175,6 @@ namespace ts {
2515125175
!isTypeAssignableTo(links.resolvedType, stringNumberSymbolType)) {
2515225176
error(node, Diagnostics.A_computed_property_name_must_be_of_type_string_number_symbol_or_any);
2515325177
}
25154-
else {
25155-
checkThatExpressionIsProperSymbolReference(node.expression, links.resolvedType, /*reportError*/ true);
25156-
}
2515725178
}
2515825179

2515925180
return links.resolvedType;
@@ -25214,15 +25235,15 @@ namespace ts {
2521425235
// As otherwise they may not be checked until exports for the type at this position are retrieved,
2521525236
// which may never occur.
2521625237
for (const elem of node.properties) {
25217-
if (elem.name && isComputedPropertyName(elem.name) && !isWellKnownSymbolSyntactically(elem.name)) {
25238+
if (elem.name && isComputedPropertyName(elem.name)) {
2521825239
checkComputedPropertyName(elem.name);
2521925240
}
2522025241
}
2522125242

2522225243
let offset = 0;
2522325244
for (const memberDecl of node.properties) {
2522425245
let member = getSymbolOfNode(memberDecl);
25225-
const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName && !isWellKnownSymbolSyntactically(memberDecl.name.expression) ?
25246+
const computedNameType = memberDecl.name && memberDecl.name.kind === SyntaxKind.ComputedPropertyName ?
2522625247
checkComputedPropertyName(memberDecl.name) : undefined;
2522725248
if (memberDecl.kind === SyntaxKind.PropertyAssignment ||
2522825249
memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ||
@@ -25321,7 +25342,10 @@ namespace ts {
2532125342
}
2532225343

2532325344
if (computedNameType && !(computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique)) {
25324-
if (isTypeAssignableTo(computedNameType, stringNumberSymbolType)) {
25345+
if (isTypeAny(computedNameType)) {
25346+
hasComputedStringProperty = true; // string is the closest to a catch-all index signature we have
25347+
}
25348+
else if (isTypeAssignableTo(computedNameType, stringNumberSymbolType)) {
2532525349
if (isTypeAssignableTo(computedNameType, numberType)) {
2532625350
hasComputedNumberProperty = true;
2532725351
}
@@ -26879,48 +26903,6 @@ namespace ts {
2687926903
return checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, indexedAccessType.symbol, indexedAccessType, indexExpression), node);
2688026904
}
2688126905

26882-
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
26883-
if (expressionType === errorType) {
26884-
// There is already an error, so no need to report one.
26885-
return false;
26886-
}
26887-
26888-
if (!isWellKnownSymbolSyntactically(expression)) {
26889-
return false;
26890-
}
26891-
26892-
// Make sure the property type is the primitive symbol type
26893-
if ((expressionType.flags & TypeFlags.ESSymbolLike) === 0) {
26894-
if (reportError) {
26895-
error(expression, Diagnostics.A_computed_property_name_of_the_form_0_must_be_of_type_symbol, getTextOfNode(expression));
26896-
}
26897-
return false;
26898-
}
26899-
26900-
// The name is Symbol.<someName>, so make sure Symbol actually resolves to the
26901-
// global Symbol object
26902-
const leftHandSide = <Identifier>(<PropertyAccessExpression>expression).expression;
26903-
const leftHandSideSymbol = getResolvedSymbol(leftHandSide);
26904-
if (!leftHandSideSymbol) {
26905-
return false;
26906-
}
26907-
26908-
const globalESSymbol = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ true);
26909-
if (!globalESSymbol) {
26910-
// Already errored when we tried to look up the symbol
26911-
return false;
26912-
}
26913-
26914-
if (leftHandSideSymbol !== globalESSymbol) {
26915-
if (reportError) {
26916-
error(leftHandSide, Diagnostics.Symbol_reference_does_not_refer_to_the_global_Symbol_constructor_object);
26917-
}
26918-
return false;
26919-
}
26920-
26921-
return true;
26922-
}
26923-
2692426906
function callLikeExpressionMayHaveTypeArguments(node: CallLikeExpression): node is CallExpression | NewExpression | TaggedTemplateExpression | JsxOpeningElement {
2692526907
return isCallOrNewExpression(node) || isTaggedTemplateExpression(node) || isJsxOpeningLikeElement(node);
2692626908
}
@@ -35198,6 +35180,12 @@ namespace ts {
3519835180
}
3519935181
}
3520035182

35183+
function getPropertyNameForKnownSymbolName(symbolName: string): __String {
35184+
const ctorType = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ false);
35185+
const uniqueType = ctorType && getTypeOfPropertyOfType(getTypeOfSymbol(ctorType), escapeLeadingUnderscores(symbolName));
35186+
return uniqueType && isTypeUsableAsPropertyName(uniqueType) ? getPropertyNameFromType(uniqueType) : `__@${symbolName}` as __String;
35187+
}
35188+
3520135189
/**
3520235190
* Gets the *yield*, *return*, and *next* types of an `Iterable`-like or `AsyncIterable`-like
3520335191
* type from its members.

src/compiler/transformers/utilities.ts

Lines 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 {

src/compiler/types.ts

Lines 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 */

src/compiler/utilities.ts

Lines changed: 3 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2244,9 +2244,7 @@ namespace ts {
22442244

22452245
/** x[0] OR x['a'] OR x[Symbol.y] */
22462246
export function isLiteralLikeElementAccess(node: Node): node is LiteralLikeElementAccessExpression {
2247-
return isElementAccessExpression(node) && (
2248-
isStringOrNumericLiteralLike(node.argumentExpression) ||
2249-
isWellKnownSymbolSyntactically(node.argumentExpression));
2247+
return isElementAccessExpression(node) && isStringOrNumericLiteralLike(node.argumentExpression);
22502248
}
22512249

22522250
/** Any series of property and element accesses. */
@@ -2331,9 +2329,6 @@ namespace ts {
23312329
return escapeLeadingUnderscores(name.text);
23322330
}
23332331
}
2334-
if (isElementAccessExpression(node) && isWellKnownSymbolSyntactically(node.argumentExpression)) {
2335-
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>node.argumentExpression).name));
2336-
}
23372332
return undefined;
23382333
}
23392334

@@ -3142,9 +3137,6 @@ namespace ts {
31423137
* 3. The computed name is *not* expressed as a NumericLiteral.
31433138
* 4. The computed name is *not* expressed as a PlusToken or MinusToken
31443139
* immediately followed by a NumericLiteral.
3145-
* 5. The computed name is *not* expressed as `Symbol.<name>`, where `<name>`
3146-
* is a property of the Symbol constructor that denotes a built-in
3147-
* Symbol.
31483140
*/
31493141
export function hasDynamicName(declaration: Declaration): declaration is DynamicNamedDeclaration | DynamicNamedBinaryExpression {
31503142
const name = getNameOfDeclaration(declaration);
@@ -3157,17 +3149,7 @@ namespace ts {
31573149
}
31583150
const expr = isElementAccessExpression(name) ? skipParentheses(name.argumentExpression) : name.expression;
31593151
return !isStringOrNumericLiteralLike(expr) &&
3160-
!isSignedNumericLiteral(expr) &&
3161-
!isWellKnownSymbolSyntactically(expr);
3162-
}
3163-
3164-
/**
3165-
* Checks if the expression is of the form:
3166-
* Symbol.name
3167-
* where Symbol is literally the word "Symbol", and name is any identifierName
3168-
*/
3169-
export function isWellKnownSymbolSyntactically(node: Node): node is WellKnownSymbolExpression {
3170-
return isPropertyAccessExpression(node) && isESSymbolIdentifier(node.expression);
3152+
!isSignedNumericLiteral(expr);
31713153
}
31723154

31733155
export function getPropertyNameForPropertyNameNode(name: PropertyName): __String | undefined {
@@ -3180,10 +3162,7 @@ namespace ts {
31803162
return escapeLeadingUnderscores(name.text);
31813163
case SyntaxKind.ComputedPropertyName:
31823164
const nameExpression = name.expression;
3183-
if (isWellKnownSymbolSyntactically(nameExpression)) {
3184-
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>nameExpression).name));
3185-
}
3186-
else if (isStringOrNumericLiteralLike(nameExpression)) {
3165+
if (isStringOrNumericLiteralLike(nameExpression)) {
31873166
return escapeLeadingUnderscores(nameExpression.text);
31883167
}
31893168
else if (isSignedNumericLiteral(nameExpression)) {
@@ -3221,10 +3200,6 @@ namespace ts {
32213200
return `__@${getSymbolId(symbol)}@${symbol.escapedName}` as __String;
32223201
}
32233202

3224-
export function getPropertyNameForKnownSymbolName(symbolName: string): __String {
3225-
return "__@" + symbolName as __String;
3226-
}
3227-
32283203
export function getSymbolNameForPrivateIdentifier(containingClassSymbol: Symbol, description: __String): __String {
32293204
return `__#${getSymbolId(containingClassSymbol)}@${description}` as __String;
32303205
}

0 commit comments

Comments
 (0)