diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 978014a99961e..8adb05f7a9ca9 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -51,6 +51,7 @@ namespace ts { const emitResolver = createResolver(); const undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined"); + undefinedSymbol.declarations = []; const argumentsSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "arguments"); const checker: TypeChecker = { @@ -234,6 +235,10 @@ namespace ts { ResolvedReturnType } + const builtinGlobals: SymbolTable = { + [undefinedSymbol.name]: undefinedSymbol + }; + initializeTypeChecker(); return checker; @@ -360,6 +365,24 @@ namespace ts { } } + function addToSymbolTable(target: SymbolTable, source: SymbolTable, message: DiagnosticMessage) { + for (const id in source) { + if (hasProperty(source, id)) { + if (hasProperty(target, id)) { + // Error on redeclarations + forEach(target[id].declarations, addDeclarationDiagnostic(id, message)); + } + else { + target[id] = source[id]; + } + } + } + + function addDeclarationDiagnostic(id: string, message: DiagnosticMessage) { + return (declaration: Declaration) => diagnostics.add(createDiagnosticForNode(declaration, message, id)); + } + } + function getSymbolLinks(symbol: Symbol): SymbolLinks { if (symbol.flags & SymbolFlags.Transient) return symbol; const id = getSymbolId(symbol); @@ -15331,10 +15354,12 @@ namespace ts { } }); + // Setup global builtins + addToSymbolTable(globals, builtinGlobals, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0); + getSymbolLinks(undefinedSymbol).type = undefinedType; getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments"); getSymbolLinks(unknownSymbol).type = unknownType; - globals[undefinedSymbol.name] = undefinedSymbol; // Initialize special types globalArrayType = getGlobalType("Array", /*arity*/ 1); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index f977ce3a86ee5..86f0767c96122 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1188,6 +1188,10 @@ "category": "Error", "code": 2396 }, + "Declaration name conflicts with built-in global identifier '{0}'.": { + "category": "Error", + "code": 2397 + }, "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference.": { "category": "Error", "code": 2399 diff --git a/tests/baselines/reference/undefinedTypeAssignment1.errors.txt b/tests/baselines/reference/undefinedTypeAssignment1.errors.txt new file mode 100644 index 0000000000000..b8dd74a58a8da --- /dev/null +++ b/tests/baselines/reference/undefinedTypeAssignment1.errors.txt @@ -0,0 +1,11 @@ +tests/cases/compiler/undefinedTypeAssignment1.ts(1,1): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. + + +==== tests/cases/compiler/undefinedTypeAssignment1.ts (1 errors) ==== + type undefined = string; + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. + function p(undefined = "wat") { + return undefined; + } + \ No newline at end of file diff --git a/tests/baselines/reference/undefinedTypeAssignment1.js b/tests/baselines/reference/undefinedTypeAssignment1.js new file mode 100644 index 0000000000000..1f53c4f6c455a --- /dev/null +++ b/tests/baselines/reference/undefinedTypeAssignment1.js @@ -0,0 +1,12 @@ +//// [undefinedTypeAssignment1.ts] +type undefined = string; +function p(undefined = "wat") { + return undefined; +} + + +//// [undefinedTypeAssignment1.js] +function p(undefined) { + if (undefined === void 0) { undefined = "wat"; } + return undefined; +} diff --git a/tests/baselines/reference/undefinedTypeAssignment2.errors.txt b/tests/baselines/reference/undefinedTypeAssignment2.errors.txt new file mode 100644 index 0000000000000..55fdbf0fc1bb3 --- /dev/null +++ b/tests/baselines/reference/undefinedTypeAssignment2.errors.txt @@ -0,0 +1,8 @@ +tests/cases/compiler/undefinedTypeAssignment2.ts(1,5): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. + + +==== tests/cases/compiler/undefinedTypeAssignment2.ts (1 errors) ==== + var undefined = void 0; + ~~~~~~~~~ +!!! error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. + \ No newline at end of file diff --git a/tests/baselines/reference/undefinedTypeAssignment2.js b/tests/baselines/reference/undefinedTypeAssignment2.js new file mode 100644 index 0000000000000..040bc8c800d30 --- /dev/null +++ b/tests/baselines/reference/undefinedTypeAssignment2.js @@ -0,0 +1,6 @@ +//// [undefinedTypeAssignment2.ts] +var undefined = void 0; + + +//// [undefinedTypeAssignment2.js] +var undefined = void 0; diff --git a/tests/baselines/reference/undefinedTypeAssignment3.errors.txt b/tests/baselines/reference/undefinedTypeAssignment3.errors.txt new file mode 100644 index 0000000000000..88df370940f2b --- /dev/null +++ b/tests/baselines/reference/undefinedTypeAssignment3.errors.txt @@ -0,0 +1,8 @@ +tests/cases/compiler/undefinedTypeAssignment3.ts(1,5): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. + + +==== tests/cases/compiler/undefinedTypeAssignment3.ts (1 errors) ==== + var undefined = null; + ~~~~~~~~~ +!!! error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. + \ No newline at end of file diff --git a/tests/baselines/reference/undefinedTypeAssignment3.js b/tests/baselines/reference/undefinedTypeAssignment3.js new file mode 100644 index 0000000000000..4015d49e33a30 --- /dev/null +++ b/tests/baselines/reference/undefinedTypeAssignment3.js @@ -0,0 +1,6 @@ +//// [undefinedTypeAssignment3.ts] +var undefined = null; + + +//// [undefinedTypeAssignment3.js] +var undefined = null; diff --git a/tests/baselines/reference/undefinedTypeAssignment4.errors.txt b/tests/baselines/reference/undefinedTypeAssignment4.errors.txt new file mode 100644 index 0000000000000..dab6ea2a880ce --- /dev/null +++ b/tests/baselines/reference/undefinedTypeAssignment4.errors.txt @@ -0,0 +1,24 @@ +tests/cases/compiler/undefinedTypeAssignment4.ts(1,7): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. +tests/cases/compiler/undefinedTypeAssignment4.ts(4,11): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. +tests/cases/compiler/undefinedTypeAssignment4.ts(7,11): error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. + + +==== tests/cases/compiler/undefinedTypeAssignment4.ts (3 errors) ==== + class undefined { + ~~~~~~~~~ +!!! error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. + foo: string; + } + interface undefined { + ~~~~~~~~~ +!!! error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. + member: number; + } + namespace undefined { + ~~~~~~~~~ +!!! error TS2397: Declaration name conflicts with built-in global identifier 'undefined'. + export var x = 42; + } + var x: undefined; + var y: typeof undefined; + \ No newline at end of file diff --git a/tests/baselines/reference/undefinedTypeAssignment4.js b/tests/baselines/reference/undefinedTypeAssignment4.js new file mode 100644 index 0000000000000..186afd872c3e6 --- /dev/null +++ b/tests/baselines/reference/undefinedTypeAssignment4.js @@ -0,0 +1,26 @@ +//// [undefinedTypeAssignment4.ts] +class undefined { + foo: string; +} +interface undefined { + member: number; +} +namespace undefined { + export var x = 42; +} +var x: undefined; +var y: typeof undefined; + + +//// [undefinedTypeAssignment4.js] +var undefined = (function () { + function undefined() { + } + return undefined; +})(); +var undefined; +(function (undefined) { + undefined.x = 42; +})(undefined || (undefined = {})); +var x; +var y; diff --git a/tests/cases/compiler/undefinedTypeAssignment1.ts b/tests/cases/compiler/undefinedTypeAssignment1.ts new file mode 100644 index 0000000000000..7d340daba69d8 --- /dev/null +++ b/tests/cases/compiler/undefinedTypeAssignment1.ts @@ -0,0 +1,4 @@ +type undefined = string; +function p(undefined = "wat") { + return undefined; +} diff --git a/tests/cases/compiler/undefinedTypeAssignment2.ts b/tests/cases/compiler/undefinedTypeAssignment2.ts new file mode 100644 index 0000000000000..3f42068e24e2e --- /dev/null +++ b/tests/cases/compiler/undefinedTypeAssignment2.ts @@ -0,0 +1 @@ +var undefined = void 0; diff --git a/tests/cases/compiler/undefinedTypeAssignment3.ts b/tests/cases/compiler/undefinedTypeAssignment3.ts new file mode 100644 index 0000000000000..8bada4f946c42 --- /dev/null +++ b/tests/cases/compiler/undefinedTypeAssignment3.ts @@ -0,0 +1 @@ +var undefined = null; diff --git a/tests/cases/compiler/undefinedTypeAssignment4.ts b/tests/cases/compiler/undefinedTypeAssignment4.ts new file mode 100644 index 0000000000000..fc0dc155acdb4 --- /dev/null +++ b/tests/cases/compiler/undefinedTypeAssignment4.ts @@ -0,0 +1,11 @@ +class undefined { + foo: string; +} +interface undefined { + member: number; +} +namespace undefined { + export var x = 42; +} +var x: undefined; +var y: typeof undefined;