Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/compiler/transformers/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ import {
tryCast,
TypeAliasDeclaration,
TypeNode,
TypeOperatorNode,
TypeParameterDeclaration,
TypeReferenceNode,
unescapeLeadingUnderscores,
Expand Down Expand Up @@ -1479,7 +1480,10 @@ export function transformDeclarations(context: TransformationContext): Transform
exportMappings.push([name, nameStr]);
}
const varDecl = factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, /*initializer*/ undefined);
return factory.createVariableStatement(isNonContextualKeywordName ? undefined : [factory.createToken(SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([varDecl]));
const modifiers = isNonContextualKeywordName ? undefined : [factory.createToken(SyntaxKind.ExportKeyword)];
const isConst = isUniqueSymbolType(type);
const variableDeclarationList = factory.createVariableDeclarationList([varDecl], isConst ? NodeFlags.Const : NodeFlags.None);
return factory.createVariableStatement(modifiers, variableDeclarationList);
});
if (!exportMappings.length) {
declarations = mapDefined(declarations, declaration => factory.replaceModifiers(declaration, ModifierFlags.None));
Expand Down Expand Up @@ -1817,6 +1821,13 @@ export function transformDeclarations(context: TransformationContext): Transform
return isExportAssignment(node) || isExportDeclaration(node);
}

function isUniqueSymbolType(type: TypeNode | undefined): boolean {
return !!type &&
type.kind === SyntaxKind.TypeOperator &&
(type as TypeOperatorNode).operator === SyntaxKind.UniqueKeyword &&
(type as TypeOperatorNode).type.kind === SyntaxKind.SymbolKeyword;
}

function hasScopeMarker(statements: readonly Statement[]) {
return some(statements, isScopeMarker);
}
Expand Down
77 changes: 77 additions & 0 deletions tests/baselines/reference/uniqueSymbolReassignment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//// [tests/cases/compiler/uniqueSymbolReassignment.ts] ////

//// [uniqueSymbolReassignment.ts]
// This is a unique symbol (const + Symbol())
const mySymbol = Symbol('Symbols.mySymbol');
const Symbols = {
mySymbol
} as const;

const anotherUnique = Symbol('symbols.anotherUnique');
const Symbols2 = {
anotherUnique
} as const;

function myFunction() {}

// Attach the unique ones
myFunction.mySymbol = Symbols.mySymbol;
myFunction.anotherUnique = Symbols2.anotherUnique;

// Non-unique symbols (regular Symbol() without const)
let nonUniqueSymbol1 = Symbol('nonUnique1');
let nonUniqueSymbol2 = Symbol('nonUnique2');

// Plain text variables (not symbols at all)
const normalVar = "not a symbol";
const symbolName = "this contains symbol but is not one";

// Attach those as well
myFunction.nonUnique1 = nonUniqueSymbol1;
myFunction.nonUnique2 = nonUniqueSymbol2;
myFunction.normalVar = normalVar;
myFunction.symbolName = symbolName;

export { myFunction };

//// [uniqueSymbolReassignment.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.myFunction = myFunction;
// This is a unique symbol (const + Symbol())
var mySymbol = Symbol('Symbols.mySymbol');
var Symbols = {
mySymbol: mySymbol
};
var anotherUnique = Symbol('symbols.anotherUnique');
var Symbols2 = {
anotherUnique: anotherUnique
};
function myFunction() { }
// Attach the unique ones
myFunction.mySymbol = Symbols.mySymbol;
myFunction.anotherUnique = Symbols2.anotherUnique;
// Non-unique symbols (regular Symbol() without const)
var nonUniqueSymbol1 = Symbol('nonUnique1');
var nonUniqueSymbol2 = Symbol('nonUnique2');
// Plain text variables (not symbols at all)
var normalVar = "not a symbol";
var symbolName = "this contains symbol but is not one";
// Attach those as well
myFunction.nonUnique1 = nonUniqueSymbol1;
myFunction.nonUnique2 = nonUniqueSymbol2;
myFunction.normalVar = normalVar;
myFunction.symbolName = symbolName;


//// [uniqueSymbolReassignment.d.ts]
declare function myFunction(): void;
declare namespace myFunction {
const mySymbol: unique symbol;
const anotherUnique: unique symbol;
var nonUnique1: symbol;
var nonUnique2: symbol;
var normalVar: string;
var symbolName: string;
}
export { myFunction };
94 changes: 94 additions & 0 deletions tests/baselines/reference/uniqueSymbolReassignment.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//// [tests/cases/compiler/uniqueSymbolReassignment.ts] ////

=== uniqueSymbolReassignment.ts ===
// This is a unique symbol (const + Symbol())
const mySymbol = Symbol('Symbols.mySymbol');
>mySymbol : Symbol(mySymbol, Decl(uniqueSymbolReassignment.ts, 1, 5))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))

const Symbols = {
>Symbols : Symbol(Symbols, Decl(uniqueSymbolReassignment.ts, 2, 5))

mySymbol
>mySymbol : Symbol(mySymbol, Decl(uniqueSymbolReassignment.ts, 2, 17))

} as const;
>const : Symbol(const)

const anotherUnique = Symbol('symbols.anotherUnique');
>anotherUnique : Symbol(anotherUnique, Decl(uniqueSymbolReassignment.ts, 6, 5))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))

const Symbols2 = {
>Symbols2 : Symbol(Symbols2, Decl(uniqueSymbolReassignment.ts, 7, 5))

anotherUnique
>anotherUnique : Symbol(anotherUnique, Decl(uniqueSymbolReassignment.ts, 7, 18))

} as const;
>const : Symbol(const)

function myFunction() {}
>myFunction : Symbol(myFunction, Decl(uniqueSymbolReassignment.ts, 9, 11), Decl(uniqueSymbolReassignment.ts, 11, 24), Decl(uniqueSymbolReassignment.ts, 14, 39), Decl(uniqueSymbolReassignment.ts, 23, 57), Decl(uniqueSymbolReassignment.ts, 26, 41) ... and 2 more)

// Attach the unique ones
myFunction.mySymbol = Symbols.mySymbol;
>myFunction.mySymbol : Symbol(myFunction.mySymbol, Decl(uniqueSymbolReassignment.ts, 11, 24))
>myFunction : Symbol(myFunction, Decl(uniqueSymbolReassignment.ts, 9, 11), Decl(uniqueSymbolReassignment.ts, 11, 24), Decl(uniqueSymbolReassignment.ts, 14, 39), Decl(uniqueSymbolReassignment.ts, 23, 57), Decl(uniqueSymbolReassignment.ts, 26, 41) ... and 2 more)
>mySymbol : Symbol(myFunction.mySymbol, Decl(uniqueSymbolReassignment.ts, 11, 24))
>Symbols.mySymbol : Symbol(mySymbol, Decl(uniqueSymbolReassignment.ts, 2, 17))
>Symbols : Symbol(Symbols, Decl(uniqueSymbolReassignment.ts, 2, 5))
>mySymbol : Symbol(mySymbol, Decl(uniqueSymbolReassignment.ts, 2, 17))

myFunction.anotherUnique = Symbols2.anotherUnique;
>myFunction.anotherUnique : Symbol(myFunction.anotherUnique, Decl(uniqueSymbolReassignment.ts, 14, 39))
>myFunction : Symbol(myFunction, Decl(uniqueSymbolReassignment.ts, 9, 11), Decl(uniqueSymbolReassignment.ts, 11, 24), Decl(uniqueSymbolReassignment.ts, 14, 39), Decl(uniqueSymbolReassignment.ts, 23, 57), Decl(uniqueSymbolReassignment.ts, 26, 41) ... and 2 more)
>anotherUnique : Symbol(myFunction.anotherUnique, Decl(uniqueSymbolReassignment.ts, 14, 39))
>Symbols2.anotherUnique : Symbol(anotherUnique, Decl(uniqueSymbolReassignment.ts, 7, 18))
>Symbols2 : Symbol(Symbols2, Decl(uniqueSymbolReassignment.ts, 7, 5))
>anotherUnique : Symbol(anotherUnique, Decl(uniqueSymbolReassignment.ts, 7, 18))

// Non-unique symbols (regular Symbol() without const)
let nonUniqueSymbol1 = Symbol('nonUnique1');
>nonUniqueSymbol1 : Symbol(nonUniqueSymbol1, Decl(uniqueSymbolReassignment.ts, 18, 3))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))

let nonUniqueSymbol2 = Symbol('nonUnique2');
>nonUniqueSymbol2 : Symbol(nonUniqueSymbol2, Decl(uniqueSymbolReassignment.ts, 19, 3))
>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --))

// Plain text variables (not symbols at all)
const normalVar = "not a symbol";
>normalVar : Symbol(normalVar, Decl(uniqueSymbolReassignment.ts, 22, 5))

const symbolName = "this contains symbol but is not one";
>symbolName : Symbol(symbolName, Decl(uniqueSymbolReassignment.ts, 23, 5))

// Attach those as well
myFunction.nonUnique1 = nonUniqueSymbol1;
>myFunction.nonUnique1 : Symbol(myFunction.nonUnique1, Decl(uniqueSymbolReassignment.ts, 23, 57))
>myFunction : Symbol(myFunction, Decl(uniqueSymbolReassignment.ts, 9, 11), Decl(uniqueSymbolReassignment.ts, 11, 24), Decl(uniqueSymbolReassignment.ts, 14, 39), Decl(uniqueSymbolReassignment.ts, 23, 57), Decl(uniqueSymbolReassignment.ts, 26, 41) ... and 2 more)
>nonUnique1 : Symbol(myFunction.nonUnique1, Decl(uniqueSymbolReassignment.ts, 23, 57))
>nonUniqueSymbol1 : Symbol(nonUniqueSymbol1, Decl(uniqueSymbolReassignment.ts, 18, 3))

myFunction.nonUnique2 = nonUniqueSymbol2;
>myFunction.nonUnique2 : Symbol(myFunction.nonUnique2, Decl(uniqueSymbolReassignment.ts, 26, 41))
>myFunction : Symbol(myFunction, Decl(uniqueSymbolReassignment.ts, 9, 11), Decl(uniqueSymbolReassignment.ts, 11, 24), Decl(uniqueSymbolReassignment.ts, 14, 39), Decl(uniqueSymbolReassignment.ts, 23, 57), Decl(uniqueSymbolReassignment.ts, 26, 41) ... and 2 more)
>nonUnique2 : Symbol(myFunction.nonUnique2, Decl(uniqueSymbolReassignment.ts, 26, 41))
>nonUniqueSymbol2 : Symbol(nonUniqueSymbol2, Decl(uniqueSymbolReassignment.ts, 19, 3))

myFunction.normalVar = normalVar;
>myFunction.normalVar : Symbol(myFunction.normalVar, Decl(uniqueSymbolReassignment.ts, 27, 41))
>myFunction : Symbol(myFunction, Decl(uniqueSymbolReassignment.ts, 9, 11), Decl(uniqueSymbolReassignment.ts, 11, 24), Decl(uniqueSymbolReassignment.ts, 14, 39), Decl(uniqueSymbolReassignment.ts, 23, 57), Decl(uniqueSymbolReassignment.ts, 26, 41) ... and 2 more)
>normalVar : Symbol(myFunction.normalVar, Decl(uniqueSymbolReassignment.ts, 27, 41))
>normalVar : Symbol(normalVar, Decl(uniqueSymbolReassignment.ts, 22, 5))

myFunction.symbolName = symbolName;
>myFunction.symbolName : Symbol(myFunction.symbolName, Decl(uniqueSymbolReassignment.ts, 28, 33))
>myFunction : Symbol(myFunction, Decl(uniqueSymbolReassignment.ts, 9, 11), Decl(uniqueSymbolReassignment.ts, 11, 24), Decl(uniqueSymbolReassignment.ts, 14, 39), Decl(uniqueSymbolReassignment.ts, 23, 57), Decl(uniqueSymbolReassignment.ts, 26, 41) ... and 2 more)
>symbolName : Symbol(myFunction.symbolName, Decl(uniqueSymbolReassignment.ts, 28, 33))
>symbolName : Symbol(symbolName, Decl(uniqueSymbolReassignment.ts, 23, 5))

export { myFunction };
>myFunction : Symbol(myFunction, Decl(uniqueSymbolReassignment.ts, 31, 8))

176 changes: 176 additions & 0 deletions tests/baselines/reference/uniqueSymbolReassignment.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//// [tests/cases/compiler/uniqueSymbolReassignment.ts] ////

=== uniqueSymbolReassignment.ts ===
// This is a unique symbol (const + Symbol())
const mySymbol = Symbol('Symbols.mySymbol');
>mySymbol : unique symbol
> : ^^^^^^^^^^^^^
>Symbol('Symbols.mySymbol') : unique symbol
> : ^^^^^^^^^^^^^
>Symbol : SymbolConstructor
> : ^^^^^^^^^^^^^^^^^
>'Symbols.mySymbol' : "Symbols.mySymbol"
> : ^^^^^^^^^^^^^^^^^^

const Symbols = {
>Symbols : { readonly mySymbol: unique symbol; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ mySymbol} as const : { readonly mySymbol: unique symbol; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ mySymbol} : { readonly mySymbol: unique symbol; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

mySymbol
>mySymbol : unique symbol
> : ^^^^^^^^^^^^^

} as const;

const anotherUnique = Symbol('symbols.anotherUnique');
>anotherUnique : unique symbol
> : ^^^^^^^^^^^^^
>Symbol('symbols.anotherUnique') : unique symbol
> : ^^^^^^^^^^^^^
>Symbol : SymbolConstructor
> : ^^^^^^^^^^^^^^^^^
>'symbols.anotherUnique' : "symbols.anotherUnique"
> : ^^^^^^^^^^^^^^^^^^^^^^^

const Symbols2 = {
>Symbols2 : { readonly anotherUnique: unique symbol; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ anotherUnique} as const : { readonly anotherUnique: unique symbol; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>{ anotherUnique} : { readonly anotherUnique: unique symbol; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

anotherUnique
>anotherUnique : unique symbol
> : ^^^^^^^^^^^^^

} as const;

function myFunction() {}
>myFunction : typeof myFunction
> : ^^^^^^^^^^^^^^^^^

// Attach the unique ones
myFunction.mySymbol = Symbols.mySymbol;
>myFunction.mySymbol = Symbols.mySymbol : unique symbol
> : ^^^^^^^^^^^^^
>myFunction.mySymbol : unique symbol
> : ^^^^^^^^^^^^^
>myFunction : typeof myFunction
> : ^^^^^^^^^^^^^^^^^
>mySymbol : unique symbol
> : ^^^^^^^^^^^^^
>Symbols.mySymbol : unique symbol
> : ^^^^^^^^^^^^^
>Symbols : { readonly mySymbol: unique symbol; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>mySymbol : unique symbol
> : ^^^^^^^^^^^^^

myFunction.anotherUnique = Symbols2.anotherUnique;
>myFunction.anotherUnique = Symbols2.anotherUnique : unique symbol
> : ^^^^^^^^^^^^^
>myFunction.anotherUnique : unique symbol
> : ^^^^^^^^^^^^^
>myFunction : typeof myFunction
> : ^^^^^^^^^^^^^^^^^
>anotherUnique : unique symbol
> : ^^^^^^^^^^^^^
>Symbols2.anotherUnique : unique symbol
> : ^^^^^^^^^^^^^
>Symbols2 : { readonly anotherUnique: unique symbol; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>anotherUnique : unique symbol
> : ^^^^^^^^^^^^^

// Non-unique symbols (regular Symbol() without const)
let nonUniqueSymbol1 = Symbol('nonUnique1');
>nonUniqueSymbol1 : symbol
> : ^^^^^^
>Symbol('nonUnique1') : symbol
> : ^^^^^^
>Symbol : SymbolConstructor
> : ^^^^^^^^^^^^^^^^^
>'nonUnique1' : "nonUnique1"
> : ^^^^^^^^^^^^

let nonUniqueSymbol2 = Symbol('nonUnique2');
>nonUniqueSymbol2 : symbol
> : ^^^^^^
>Symbol('nonUnique2') : symbol
> : ^^^^^^
>Symbol : SymbolConstructor
> : ^^^^^^^^^^^^^^^^^
>'nonUnique2' : "nonUnique2"
> : ^^^^^^^^^^^^

// Plain text variables (not symbols at all)
const normalVar = "not a symbol";
>normalVar : "not a symbol"
> : ^^^^^^^^^^^^^^
>"not a symbol" : "not a symbol"
> : ^^^^^^^^^^^^^^

const symbolName = "this contains symbol but is not one";
>symbolName : "this contains symbol but is not one"
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>"this contains symbol but is not one" : "this contains symbol but is not one"
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

// Attach those as well
myFunction.nonUnique1 = nonUniqueSymbol1;
>myFunction.nonUnique1 = nonUniqueSymbol1 : symbol
> : ^^^^^^
>myFunction.nonUnique1 : symbol
> : ^^^^^^
>myFunction : typeof myFunction
> : ^^^^^^^^^^^^^^^^^
>nonUnique1 : symbol
> : ^^^^^^
>nonUniqueSymbol1 : symbol
> : ^^^^^^

myFunction.nonUnique2 = nonUniqueSymbol2;
>myFunction.nonUnique2 = nonUniqueSymbol2 : symbol
> : ^^^^^^
>myFunction.nonUnique2 : symbol
> : ^^^^^^
>myFunction : typeof myFunction
> : ^^^^^^^^^^^^^^^^^
>nonUnique2 : symbol
> : ^^^^^^
>nonUniqueSymbol2 : symbol
> : ^^^^^^

myFunction.normalVar = normalVar;
>myFunction.normalVar = normalVar : "not a symbol"
> : ^^^^^^^^^^^^^^
>myFunction.normalVar : string
> : ^^^^^^
>myFunction : typeof myFunction
> : ^^^^^^^^^^^^^^^^^
>normalVar : string
> : ^^^^^^
>normalVar : "not a symbol"
> : ^^^^^^^^^^^^^^

myFunction.symbolName = symbolName;
>myFunction.symbolName = symbolName : "this contains symbol but is not one"
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>myFunction.symbolName : string
> : ^^^^^^
>myFunction : typeof myFunction
> : ^^^^^^^^^^^^^^^^^
>symbolName : string
> : ^^^^^^
>symbolName : "this contains symbol but is not one"
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

export { myFunction };
>myFunction : typeof myFunction
> : ^^^^^^^^^^^^^^^^^

Loading
Loading