diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8d144266b8bbd..7d848b2de491f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2255,9 +2255,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var identityRelation = new Map(); var enumRelation = new Map(); - var builtinGlobals = createSymbolTable(); - builtinGlobals.set(undefinedSymbol.escapedName, undefinedSymbol); - // Extensions suggested for path imports when module resolution is node16 or higher. // The first element of each tuple is the extension a file has. // The second element of each tuple is the extension that should be used in a path import. @@ -2720,20 +2717,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function addToSymbolTable(target: SymbolTable, source: SymbolTable, message: DiagnosticMessage) { - source.forEach((sourceSymbol, id) => { - const targetSymbol = target.get(id); - if (targetSymbol) { - // Error on redeclarations - forEach(targetSymbol.declarations, addDeclarationDiagnostic(unescapeLeadingUnderscores(id), message)); - } - else { - target.set(id, sourceSymbol); - } - }); - - function addDeclarationDiagnostic(id: string, message: DiagnosticMessage) { - return (declaration: Declaration) => diagnostics.add(createDiagnosticForNode(declaration, message, id)); + function addUndefinedToGlobalsOrErrorOnRedeclaration() { + const name = undefinedSymbol.escapedName; + const targetSymbol = globals.get(name); + if (targetSymbol) { + forEach(targetSymbol.declarations, declaration => { + // checkTypeNameIsReserved will have added better diagnostics for type declarations. + if (!isTypeDeclaration(declaration)) { + diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, unescapeLeadingUnderscores(name))); + } + }); + } + else { + globals.set(name, undefinedSymbol); } } @@ -44320,6 +44316,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case "symbol": case "void": case "object": + case "undefined": error(name, message, name.escapedText as string); } } @@ -48749,7 +48746,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (!isExternalOrCommonJsModule(file)) { // It is an error for a non-external-module (i.e. script) to declare its own `globalThis`. - // We can't use `builtinGlobals` for this due to synthetic expando-namespace generation in JS files. const fileGlobalThisSymbol = file.locals!.get("globalThis" as __String); if (fileGlobalThisSymbol?.declarations) { for (const declaration of fileGlobalThisSymbol.declarations) { @@ -48795,8 +48791,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - // Setup global builtins - addToSymbolTable(globals, builtinGlobals, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0); + addUndefinedToGlobalsOrErrorOnRedeclaration(); getSymbolLinks(undefinedSymbol).type = undefinedWideningType; getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments" as __String, /*arity*/ 0, /*reportErrors*/ true); diff --git a/tests/baselines/reference/typeNamedUndefined1.errors.txt b/tests/baselines/reference/typeNamedUndefined1.errors.txt new file mode 100644 index 0000000000000..964674469fcb9 --- /dev/null +++ b/tests/baselines/reference/typeNamedUndefined1.errors.txt @@ -0,0 +1,23 @@ +typeNamedUndefined1.ts(3,17): error TS2457: Type alias name cannot be 'undefined'. +typeNamedUndefined1.ts(13,13): error TS2457: Type alias name cannot be 'undefined'. + + +==== typeNamedUndefined1.ts (2 errors) ==== + export namespace ns { + const s = Symbol(); + export type undefined = typeof s; + ~~~~~~~~~ +!!! error TS2457: Type alias name cannot be 'undefined'. + export function x(p: undefined): undefined { // global undefined + return p; + } + } + + export function x(p: ns.undefined) { // undefined from the namespace + return p; + } + + export type undefined = ""; + ~~~~~~~~~ +!!! error TS2457: Type alias name cannot be 'undefined'. + \ No newline at end of file diff --git a/tests/baselines/reference/typeNamedUndefined1.js b/tests/baselines/reference/typeNamedUndefined1.js new file mode 100644 index 0000000000000..ceb557f653b9a --- /dev/null +++ b/tests/baselines/reference/typeNamedUndefined1.js @@ -0,0 +1,30 @@ +//// [tests/cases/compiler/typeNamedUndefined1.ts] //// + +//// [typeNamedUndefined1.ts] +export namespace ns { + const s = Symbol(); + export type undefined = typeof s; + export function x(p: undefined): undefined { // global undefined + return p; + } +} + +export function x(p: ns.undefined) { // undefined from the namespace + return p; +} + +export type undefined = ""; + + +//// [typeNamedUndefined1.js] +export var ns; +(function (ns) { + const s = Symbol(); + function x(p) { + return p; + } + ns.x = x; +})(ns || (ns = {})); +export function x(p) { + return p; +} diff --git a/tests/baselines/reference/typeNamedUndefined1.symbols b/tests/baselines/reference/typeNamedUndefined1.symbols new file mode 100644 index 0000000000000..3bdf1be465c92 --- /dev/null +++ b/tests/baselines/reference/typeNamedUndefined1.symbols @@ -0,0 +1,36 @@ +//// [tests/cases/compiler/typeNamedUndefined1.ts] //// + +=== typeNamedUndefined1.ts === +export namespace ns { +>ns : Symbol(ns, Decl(typeNamedUndefined1.ts, 0, 0)) + + const s = Symbol(); +>s : Symbol(s, Decl(typeNamedUndefined1.ts, 1, 9)) +>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, --, --)) + + export type undefined = typeof s; +>undefined : Symbol(undefined, Decl(typeNamedUndefined1.ts, 1, 23)) +>s : Symbol(s, Decl(typeNamedUndefined1.ts, 1, 9)) + + export function x(p: undefined): undefined { // global undefined +>x : Symbol(x, Decl(typeNamedUndefined1.ts, 2, 37)) +>p : Symbol(p, Decl(typeNamedUndefined1.ts, 3, 22)) + + return p; +>p : Symbol(p, Decl(typeNamedUndefined1.ts, 3, 22)) + } +} + +export function x(p: ns.undefined) { // undefined from the namespace +>x : Symbol(x, Decl(typeNamedUndefined1.ts, 6, 1)) +>p : Symbol(p, Decl(typeNamedUndefined1.ts, 8, 18)) +>ns : Symbol(ns, Decl(typeNamedUndefined1.ts, 0, 0)) +>undefined : Symbol(ns.undefined, Decl(typeNamedUndefined1.ts, 1, 23)) + + return p; +>p : Symbol(p, Decl(typeNamedUndefined1.ts, 8, 18)) +} + +export type undefined = ""; +>undefined : Symbol(undefined, Decl(typeNamedUndefined1.ts, 10, 1)) + diff --git a/tests/baselines/reference/typeNamedUndefined1.types b/tests/baselines/reference/typeNamedUndefined1.types new file mode 100644 index 0000000000000..119236a141478 --- /dev/null +++ b/tests/baselines/reference/typeNamedUndefined1.types @@ -0,0 +1,36 @@ +//// [tests/cases/compiler/typeNamedUndefined1.ts] //// + +=== typeNamedUndefined1.ts === +export namespace ns { +>ns : typeof ns + + const s = Symbol(); +>s : unique symbol +>Symbol() : unique symbol +>Symbol : SymbolConstructor + + export type undefined = typeof s; +>undefined : unique symbol +>s : unique symbol + + export function x(p: undefined): undefined { // global undefined +>x : (p: undefined) => undefined +>p : undefined + + return p; +>p : undefined + } +} + +export function x(p: ns.undefined) { // undefined from the namespace +>x : (p: ns.undefined) => symbol +>p : unique symbol +>ns : any + + return p; +>p : unique symbol +} + +export type undefined = ""; +>undefined : "" + diff --git a/tests/baselines/reference/typeNamedUndefined2.errors.txt b/tests/baselines/reference/typeNamedUndefined2.errors.txt new file mode 100644 index 0000000000000..0f9ece1ec6a41 --- /dev/null +++ b/tests/baselines/reference/typeNamedUndefined2.errors.txt @@ -0,0 +1,28 @@ +typeNamedUndefined2.ts(4,21): error TS2457: Type alias name cannot be 'undefined'. +typeNamedUndefined2.ts(17,17): error TS2457: Type alias name cannot be 'undefined'. + + +==== typeNamedUndefined2.ts (2 errors) ==== + export namespace ns { + export namespace undefined { + export const s = Symbol(); + export type undefined = typeof s; + ~~~~~~~~~ +!!! error TS2457: Type alias name cannot be 'undefined'. + }; + export function x(p: undefined): undefined { + return p; + } + } + + export function x(p: ns.undefined.undefined) { + return p; + } + + export namespace undefined { + export const s = Symbol(); + export type undefined = typeof s; + ~~~~~~~~~ +!!! error TS2457: Type alias name cannot be 'undefined'. + }; + \ No newline at end of file diff --git a/tests/baselines/reference/typeNamedUndefined2.js b/tests/baselines/reference/typeNamedUndefined2.js new file mode 100644 index 0000000000000..bed8504ca1244 --- /dev/null +++ b/tests/baselines/reference/typeNamedUndefined2.js @@ -0,0 +1,44 @@ +//// [tests/cases/compiler/typeNamedUndefined2.ts] //// + +//// [typeNamedUndefined2.ts] +export namespace ns { + export namespace undefined { + export const s = Symbol(); + export type undefined = typeof s; + }; + export function x(p: undefined): undefined { + return p; + } +} + +export function x(p: ns.undefined.undefined) { + return p; +} + +export namespace undefined { + export const s = Symbol(); + export type undefined = typeof s; +}; + + +//// [typeNamedUndefined2.js] +export var ns; +(function (ns) { + let undefined; + (function (undefined) { + undefined.s = Symbol(); + })(undefined = ns.undefined || (ns.undefined = {})); + ; + function x(p) { + return p; + } + ns.x = x; +})(ns || (ns = {})); +export function x(p) { + return p; +} +export var undefined; +(function (undefined) { + undefined.s = Symbol(); +})(undefined || (undefined = {})); +; diff --git a/tests/baselines/reference/typeNamedUndefined2.symbols b/tests/baselines/reference/typeNamedUndefined2.symbols new file mode 100644 index 0000000000000..f411cffcaa2eb --- /dev/null +++ b/tests/baselines/reference/typeNamedUndefined2.symbols @@ -0,0 +1,51 @@ +//// [tests/cases/compiler/typeNamedUndefined2.ts] //// + +=== typeNamedUndefined2.ts === +export namespace ns { +>ns : Symbol(ns, Decl(typeNamedUndefined2.ts, 0, 0)) + + export namespace undefined { +>undefined : Symbol(undefined, Decl(typeNamedUndefined2.ts, 0, 21)) + + export const s = Symbol(); +>s : Symbol(s, Decl(typeNamedUndefined2.ts, 2, 20)) +>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, --, --)) + + export type undefined = typeof s; +>undefined : Symbol(undefined, Decl(typeNamedUndefined2.ts, 2, 34)) +>s : Symbol(s, Decl(typeNamedUndefined2.ts, 2, 20)) + + }; + export function x(p: undefined): undefined { +>x : Symbol(x, Decl(typeNamedUndefined2.ts, 4, 6)) +>p : Symbol(p, Decl(typeNamedUndefined2.ts, 5, 22)) + + return p; +>p : Symbol(p, Decl(typeNamedUndefined2.ts, 5, 22)) + } +} + +export function x(p: ns.undefined.undefined) { +>x : Symbol(x, Decl(typeNamedUndefined2.ts, 8, 1)) +>p : Symbol(p, Decl(typeNamedUndefined2.ts, 10, 18)) +>ns : Symbol(ns, Decl(typeNamedUndefined2.ts, 0, 0)) +>undefined : Symbol(ns.undefined, Decl(typeNamedUndefined2.ts, 0, 21)) +>undefined : Symbol(ns.undefined.undefined, Decl(typeNamedUndefined2.ts, 2, 34)) + + return p; +>p : Symbol(p, Decl(typeNamedUndefined2.ts, 10, 18)) +} + +export namespace undefined { +>undefined : Symbol(undefined, Decl(typeNamedUndefined2.ts, 12, 1)) + + export const s = Symbol(); +>s : Symbol(s, Decl(typeNamedUndefined2.ts, 15, 16)) +>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, --, --)) + + export type undefined = typeof s; +>undefined : Symbol(undefined, Decl(typeNamedUndefined2.ts, 15, 30)) +>s : Symbol(s, Decl(typeNamedUndefined2.ts, 15, 16)) + +}; + diff --git a/tests/baselines/reference/typeNamedUndefined2.types b/tests/baselines/reference/typeNamedUndefined2.types new file mode 100644 index 0000000000000..4492ad2e6d52d --- /dev/null +++ b/tests/baselines/reference/typeNamedUndefined2.types @@ -0,0 +1,52 @@ +//// [tests/cases/compiler/typeNamedUndefined2.ts] //// + +=== typeNamedUndefined2.ts === +export namespace ns { +>ns : typeof ns + + export namespace undefined { +>undefined : typeof undefined + + export const s = Symbol(); +>s : unique symbol +>Symbol() : unique symbol +>Symbol : SymbolConstructor + + export type undefined = typeof s; +>undefined : unique symbol +>s : unique symbol + + }; + export function x(p: undefined): undefined { +>x : (p: undefined) => undefined +>p : undefined + + return p; +>p : undefined + } +} + +export function x(p: ns.undefined.undefined) { +>x : (p: ns.undefined.undefined) => symbol +>p : unique symbol +>ns : any +>undefined : any + + return p; +>p : unique symbol +} + +export namespace undefined { +>undefined : typeof undefined + + export const s = Symbol(); +>s : unique symbol +>Symbol() : unique symbol +>Symbol : SymbolConstructor + + export type undefined = typeof s; +>undefined : unique symbol +>s : unique symbol + +}; + diff --git a/tests/baselines/reference/undefinedTypeAssignment1.errors.txt b/tests/baselines/reference/undefinedTypeAssignment1.errors.txt index 51a3948a14b97..dc0721a31b80b 100644 --- a/tests/baselines/reference/undefinedTypeAssignment1.errors.txt +++ b/tests/baselines/reference/undefinedTypeAssignment1.errors.txt @@ -1,10 +1,10 @@ -undefinedTypeAssignment1.ts(1,6): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. +undefinedTypeAssignment1.ts(1,6): error TS2457: Type alias name cannot be 'undefined'. ==== undefinedTypeAssignment1.ts (1 errors) ==== type undefined = string; ~~~~~~~~~ -!!! error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. +!!! error TS2457: Type alias name cannot be 'undefined'. function p(undefined = "wat") { return undefined; } diff --git a/tests/baselines/reference/undefinedTypeAssignment4.errors.txt b/tests/baselines/reference/undefinedTypeAssignment4.errors.txt index 847fe6087f6b5..4a6ff2daa4047 100644 --- a/tests/baselines/reference/undefinedTypeAssignment4.errors.txt +++ b/tests/baselines/reference/undefinedTypeAssignment4.errors.txt @@ -1,17 +1,17 @@ -undefinedTypeAssignment4.ts(1,7): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. -undefinedTypeAssignment4.ts(4,11): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. +undefinedTypeAssignment4.ts(1,7): error TS2414: Class name cannot be 'undefined'. +undefinedTypeAssignment4.ts(4,11): error TS2427: Interface name cannot be 'undefined'. undefinedTypeAssignment4.ts(7,11): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. ==== undefinedTypeAssignment4.ts (3 errors) ==== class undefined { ~~~~~~~~~ -!!! error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. +!!! error TS2414: Class name cannot be 'undefined'. foo: string; } interface undefined { ~~~~~~~~~ -!!! error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. +!!! error TS2427: Interface name cannot be 'undefined'. member: number; } namespace undefined { diff --git a/tests/cases/compiler/typeNamedUndefined1.ts b/tests/cases/compiler/typeNamedUndefined1.ts new file mode 100644 index 0000000000000..22f509f443e70 --- /dev/null +++ b/tests/cases/compiler/typeNamedUndefined1.ts @@ -0,0 +1,17 @@ +// @strict: true +// @target: esnext +// @lib: esnext + +export namespace ns { + const s = Symbol(); + export type undefined = typeof s; + export function x(p: undefined): undefined { // global undefined + return p; + } +} + +export function x(p: ns.undefined) { // undefined from the namespace + return p; +} + +export type undefined = ""; diff --git a/tests/cases/compiler/typeNamedUndefined2.ts b/tests/cases/compiler/typeNamedUndefined2.ts new file mode 100644 index 0000000000000..e0fd502e3d3d2 --- /dev/null +++ b/tests/cases/compiler/typeNamedUndefined2.ts @@ -0,0 +1,22 @@ +// @strict: true +// @target: esnext +// @lib: esnext + +export namespace ns { + export namespace undefined { + export const s = Symbol(); + export type undefined = typeof s; + }; + export function x(p: undefined): undefined { + return p; + } +} + +export function x(p: ns.undefined.undefined) { + return p; +} + +export namespace undefined { + export const s = Symbol(); + export type undefined = typeof s; +};