Skip to content

Commit

Permalink
Allow references to the global Symbol in computed property names unde…
Browse files Browse the repository at this point in the history
…r isolatedDeclarations (#58771)
  • Loading branch information
weswigham committed Jun 4, 2024
1 parent 506f3e2 commit 112e860
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 32 deletions.
15 changes: 15 additions & 0 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1511,6 +1511,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
Debug.assert(isExpressionNode(node));
return getSymbolAtLocation(node) === undefinedSymbol;
},
isDefinitelyReferenceToGlobalSymbolObject,
});
var evaluate = createEvaluator({
evaluateElementAccessExpression,
Expand Down Expand Up @@ -2350,6 +2351,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {

return checker;

function isDefinitelyReferenceToGlobalSymbolObject(node: Node): boolean {
if (!isPropertyAccessExpression(node)) return false;
if (!isIdentifier(node.name)) return false;
if (!isPropertyAccessExpression(node.expression) && !isIdentifier(node.expression)) return false;
if (isIdentifier(node.expression)) {
// Exactly `Symbol.something` and `Symbol` either does not resolve or definitely resolves to the global Symbol
return idText(node.expression) === "Symbol" && getResolvedSymbol(node.expression) === (getGlobalSymbol("Symbol" as __String, SymbolFlags.Value | SymbolFlags.ExportValue, /*diagnostic*/ undefined) || unknownSymbol);
}
if (!isIdentifier(node.expression.expression)) return false;
// Exactly `globalThis.Symbol.something` and `globalThis` resolves to the global `globalThis`
return idText(node.expression.name) === "Symbol" && idText(node.expression.expression) === "globalThis" && getResolvedSymbol(node.expression.expression) === globalThisSymbol;
}

function getCachedType(key: string | undefined) {
return key ? cachedTypes.get(key) : undefined;
}
Expand Down Expand Up @@ -49738,6 +49752,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return !sym.exports ? [] : nodeBuilder.symbolTableToDeclarationStatements(sym.exports, node, flags, tracker);
},
isImportRequiredByAugmentation,
isDefinitelyReferenceToGlobalSymbolObject,
};

function isImportRequiredByAugmentation(node: ImportDeclaration) {
Expand Down
1 change: 1 addition & 0 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,7 @@ export const notImplementedResolver: EmitResolver = {
isBindingCapturedByNode: notImplemented,
getDeclarationStatementsForSourceFile: notImplemented,
isImportRequiredByAugmentation: notImplemented,
isDefinitelyReferenceToGlobalSymbolObject: notImplemented,
};

const enum PipelinePhase {
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/expressionToTypeNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ export function createSyntacticTypeNodeBuilder(options: CompilerOptions, resolve
}
else if (prop.name.kind === SyntaxKind.ComputedPropertyName) {
const expression = prop.name.expression;
if (!isPrimitiveLiteralValue(expression, /*includeBigInt*/ false)) {
if (!isPrimitiveLiteralValue(expression, /*includeBigInt*/ false) && !resolver.isDefinitelyReferenceToGlobalSymbolObject(expression)) {
context.tracker.reportInferenceFallback(prop.name);
result = false;
}
Expand Down
24 changes: 13 additions & 11 deletions src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1000,17 +1000,19 @@ export function transformDeclarations(context: TransformationContext) {
if (isolatedDeclarations) {
// Classes and object literals usually elide properties with computed names that are not of a literal type
// In isolated declarations TSC needs to error on these as we don't know the type in a DTE.
if (isClassDeclaration(input.parent) || isObjectLiteralExpression(input.parent)) {
context.addDiagnostic(createDiagnosticForNode(input, Diagnostics.Computed_property_names_on_class_or_object_literals_cannot_be_inferred_with_isolatedDeclarations));
return;
}
else if (
// Type declarations just need to double-check that the input computed name is an entity name expression
(isInterfaceDeclaration(input.parent) || isTypeLiteralNode(input.parent))
&& !isEntityNameExpression(input.name.expression)
) {
context.addDiagnostic(createDiagnosticForNode(input, Diagnostics.Computed_properties_must_be_number_or_string_literals_variables_or_dotted_expressions_with_isolatedDeclarations));
return;
if (!resolver.isDefinitelyReferenceToGlobalSymbolObject(input.name.expression)) {
if (isClassDeclaration(input.parent) || isObjectLiteralExpression(input.parent)) {
context.addDiagnostic(createDiagnosticForNode(input, Diagnostics.Computed_property_names_on_class_or_object_literals_cannot_be_inferred_with_isolatedDeclarations));
return;
}
else if (
// Type declarations just need to double-check that the input computed name is an entity name expression
(isInterfaceDeclaration(input.parent) || isTypeLiteralNode(input.parent))
&& !isEntityNameExpression(input.name.expression)
) {
context.addDiagnostic(createDiagnosticForNode(input, Diagnostics.Computed_properties_must_be_number_or_string_literals_variables_or_dotted_expressions_with_isolatedDeclarations));
return;
}
}
}
else if (!resolver.isLateBound(getParseTreeNode(input) as Declaration) || !isEntityNameExpression(input.name.expression)) {
Expand Down
2 changes: 2 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5809,6 +5809,7 @@ export interface EmitResolver {
isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean;
getDeclarationStatementsForSourceFile(node: SourceFile, flags: NodeBuilderFlags, tracker: SymbolTracker): Statement[] | undefined;
isImportRequiredByAugmentation(decl: ImportDeclaration): boolean;
isDefinitelyReferenceToGlobalSymbolObject(node: Node): boolean;
}

// dprint-ignore
Expand Down Expand Up @@ -10334,4 +10335,5 @@ export interface SyntacticTypeNodeBuilderResolver {
getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations;
isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node, shouldComputeAliasToMakeVisible?: boolean): SymbolVisibilityResult;
requiresAddingImplicitUndefined(parameter: ParameterDeclaration | JSDocParameterTag): boolean;
isDefinitelyReferenceToGlobalSymbolObject(node: Node): boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ export namespace presentNs {
export const a = Symbol();
}

const aliasing = Symbol;

export type A = {
[missing]: number,
[ns.missing]: number,
[presentNs.a]: number,
[Symbol.iterator]: number,
[globalThis.Symbol.toStringTag]: number,
[(globalThis.Symbol).unscopables]: number,
[aliasing.isConcatSpreadable]: number,
[1]: number,
["2"]: number,
[(missing2)]: number,
Expand All @@ -19,6 +24,9 @@ export interface B {
[ns.missing]: number,
[presentNs.a]: number,
[Symbol.iterator]: number,
[globalThis.Symbol.toStringTag]: number,
[(globalThis.Symbol).unscopables]: number,
[aliasing.isConcatSpreadable]: number,
[1]: number,
["2"]: number,
[(missing2)]: number,
Expand All @@ -30,6 +38,9 @@ export class C {
[ns.missing]: number = 1;
[presentNs.a]: number = 1;
[Symbol.iterator]: number = 1;
[globalThis.Symbol.toStringTag]: number = 1;
[(globalThis.Symbol).unscopables]: number = 1;
[aliasing.isConcatSpreadable]: number = 1;
[1]: number = 1;
["2"]: number = 1;
[(missing2)]: number = 1;
Expand All @@ -41,6 +52,9 @@ export const D = {
[ns.missing]: 1,
[presentNs.a]: 1,
[Symbol.iterator]: 1,
[globalThis.Symbol.toStringTag]: 1,
[(globalThis.Symbol).unscopables]: 1,
[aliasing.isConcatSpreadable]: 1,
[1]: 1,
["2"]: 1,
[(missing2)]: 1,
Expand All @@ -50,11 +64,14 @@ export const D = {
export declare namespace presentNs {
const a: unique symbol;
}
declare const aliasing: SymbolConstructor;
export type A = {
[missing]: number;
[ns.missing]: number;
[presentNs.a]: number;
[Symbol.iterator]: number;
[globalThis.Symbol.toStringTag]: number;
[aliasing.isConcatSpreadable]: number;
[1]: number;
["2"]: number;
};
Expand All @@ -63,55 +80,76 @@ export interface B {
[ns.missing]: number;
[presentNs.a]: number;
[Symbol.iterator]: number;
[globalThis.Symbol.toStringTag]: number;
[aliasing.isConcatSpreadable]: number;
[1]: number;
["2"]: number;
}
export declare class C {
[Symbol.iterator]: number;
[globalThis.Symbol.toStringTag]: number;
[1]: number;
["2"]: number;
}
export declare const D: {
[x: string]: number;
[x: number]: number;
[presentNs.a]: number;
[aliasing.toStringTag]: number;
1: number;
"2": number;
};
export {};


//// [Diagnostics reported]
declarationComputedPropertyNames.ts(2,18): error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations.
declarationComputedPropertyNames.ts(12,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
declarationComputedPropertyNames.ts(5,7): error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations.
declarationComputedPropertyNames.ts(13,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
declarationComputedPropertyNames.ts(23,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
declarationComputedPropertyNames.ts(24,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
declarationComputedPropertyNames.ts(28,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(29,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(30,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(31,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(34,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(35,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(39,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(40,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(17,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
declarationComputedPropertyNames.ts(18,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
declarationComputedPropertyNames.ts(27,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
declarationComputedPropertyNames.ts(31,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
declarationComputedPropertyNames.ts(32,5): error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
declarationComputedPropertyNames.ts(36,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(37,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(38,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(41,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(42,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(45,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(46,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(50,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(51,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(52,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(55,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(56,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(59,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
declarationComputedPropertyNames.ts(60,5): error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.


==== declarationComputedPropertyNames.ts (17 errors) ====
==== declarationComputedPropertyNames.ts (22 errors) ====
export namespace presentNs {
export const a = Symbol();
~
!!! error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations.
!!! related TS9027 declarationComputedPropertyNames.ts:2:18: Add a type annotation to the variable a.
}

const aliasing = Symbol;
~~~~~~~~
!!! error TS9010: Variable must have an explicit type annotation with --isolatedDeclarations.
!!! related TS9027 declarationComputedPropertyNames.ts:5:7: Add a type annotation to the variable aliasing.

export type A = {
[missing]: number,
[ns.missing]: number,
[presentNs.a]: number,
[Symbol.iterator]: number,
[globalThis.Symbol.toStringTag]: number,
[(globalThis.Symbol).unscopables]: number,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
[aliasing.isConcatSpreadable]: number,
[1]: number,
["2"]: number,
[(missing2)]: number,
Expand All @@ -127,6 +165,11 @@ declarationComputedPropertyNames.ts(46,5): error TS9038: Computed property names
[ns.missing]: number,
[presentNs.a]: number,
[Symbol.iterator]: number,
[globalThis.Symbol.toStringTag]: number,
[(globalThis.Symbol).unscopables]: number,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS9014: Computed properties must be number or string literals, variables or dotted expressions with --isolatedDeclarations.
[aliasing.isConcatSpreadable]: number,
[1]: number,
["2"]: number,
[(missing2)]: number,
Expand All @@ -148,7 +191,12 @@ declarationComputedPropertyNames.ts(46,5): error TS9038: Computed property names
~~~~~~~~~~~~~
!!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
[Symbol.iterator]: number = 1;
~~~~~~~~~~~~~~~~~
[globalThis.Symbol.toStringTag]: number = 1;
[(globalThis.Symbol).unscopables]: number = 1;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
[aliasing.isConcatSpreadable]: number = 1;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
[1]: number = 1;
["2"]: number = 1;
Expand All @@ -164,28 +212,34 @@ declarationComputedPropertyNames.ts(46,5): error TS9038: Computed property names
[missing]: 1,
~~~~~~~~~
!!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
!!! related TS9027 declarationComputedPropertyNames.ts:38:14: Add a type annotation to the variable D.
!!! related TS9027 declarationComputedPropertyNames.ts:49:14: Add a type annotation to the variable D.
[ns.missing]: 1,
~~~~~~~~~~~~
!!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
!!! related TS9027 declarationComputedPropertyNames.ts:38:14: Add a type annotation to the variable D.
!!! related TS9027 declarationComputedPropertyNames.ts:49:14: Add a type annotation to the variable D.
[presentNs.a]: 1,
~~~~~~~~~~~~~
!!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
!!! related TS9027 declarationComputedPropertyNames.ts:38:14: Add a type annotation to the variable D.
!!! related TS9027 declarationComputedPropertyNames.ts:49:14: Add a type annotation to the variable D.
[Symbol.iterator]: 1,
~~~~~~~~~~~~~~~~~
[globalThis.Symbol.toStringTag]: 1,
[(globalThis.Symbol).unscopables]: 1,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
!!! related TS9027 declarationComputedPropertyNames.ts:49:14: Add a type annotation to the variable D.
[aliasing.isConcatSpreadable]: 1,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
!!! related TS9027 declarationComputedPropertyNames.ts:38:14: Add a type annotation to the variable D.
!!! related TS9027 declarationComputedPropertyNames.ts:49:14: Add a type annotation to the variable D.
[1]: 1,
["2"]: 1,
[(missing2)]: 1,
~~~~~~~~~~~~
!!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
!!! related TS9027 declarationComputedPropertyNames.ts:38:14: Add a type annotation to the variable D.
!!! related TS9027 declarationComputedPropertyNames.ts:49:14: Add a type annotation to the variable D.
[Math.random() > 0.5 ? "f1" : "f2"]: 1,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS9038: Computed property names on class or object literals cannot be inferred with --isolatedDeclarations.
!!! related TS9027 declarationComputedPropertyNames.ts:38:14: Add a type annotation to the variable D.
!!! related TS9027 declarationComputedPropertyNames.ts:49:14: Add a type annotation to the variable D.
};

Loading

0 comments on commit 112e860

Please sign in to comment.