Skip to content

Commit

Permalink
Error on types named "undefined" (#57575)
Browse files Browse the repository at this point in the history
  • Loading branch information
jakebailey committed Mar 11, 2024
1 parent 3fca8c8 commit e24d886
Show file tree
Hide file tree
Showing 13 changed files with 360 additions and 26 deletions.
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) {
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);
}
}

Expand Down Expand Up @@ -44336,6 +44332,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 @@ -48773,7 +48770,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 @@ -48819,8 +48815,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

0 comments on commit e24d886

Please sign in to comment.