Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error on types named "undefined" #57575

Merged
merged 16 commits into from
Mar 11, 2024
35 changes: 15 additions & 20 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2255,9 +2255,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
var identityRelation = new Map<string, RelationComparisonResult>();
var enumRelation = new Map<string, RelationComparisonResult>();

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.
Expand Down Expand Up @@ -2720,20 +2717,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
}

function addToSymbolTable(target: SymbolTable, source: SymbolTable, message: DiagnosticMessage) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I opted to eliminate builtinGlobals while here; its only use is to complain about undefined, but now we're going to complain even less and the new code had to exclude type declarations anyway.

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 undefined.
jakebailey marked this conversation as resolved.
Show resolved Hide resolved
if (!isTypeDeclaration(declaration)) {
diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, unescapeLeadingUnderscores(name)));
}
});
}
else {
globals.set(name, undefinedSymbol);
}
}

Expand Down Expand Up @@ -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);
}
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
23 changes: 23 additions & 0 deletions tests/baselines/reference/typeNamedUndefined1.errors.txt
Original file line number Diff line number Diff line change
@@ -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'.

30 changes: 30 additions & 0 deletions tests/baselines/reference/typeNamedUndefined1.js
Original file line number Diff line number Diff line change
@@ -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;
}
36 changes: 36 additions & 0 deletions tests/baselines/reference/typeNamedUndefined1.symbols
Original file line number Diff line number Diff line change
@@ -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))

36 changes: 36 additions & 0 deletions tests/baselines/reference/typeNamedUndefined1.types
Original file line number Diff line number Diff line change
@@ -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 : ""

28 changes: 28 additions & 0 deletions tests/baselines/reference/typeNamedUndefined2.errors.txt
Original file line number Diff line number Diff line change
@@ -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'.
};

44 changes: 44 additions & 0 deletions tests/baselines/reference/typeNamedUndefined2.js
Original file line number Diff line number Diff line change
@@ -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 = {}));
;
51 changes: 51 additions & 0 deletions tests/baselines/reference/typeNamedUndefined2.symbols
Original file line number Diff line number Diff line change
@@ -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))

};

52 changes: 52 additions & 0 deletions tests/baselines/reference/typeNamedUndefined2.types
Original file line number Diff line number Diff line change
@@ -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

};

4 changes: 2 additions & 2 deletions tests/baselines/reference/undefinedTypeAssignment1.errors.txt
Original file line number Diff line number Diff line change
@@ -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;
}
Expand Down
Loading
Loading