From d92771d61a764e884eb27b638750ae6b54dc3dae Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 30 Nov 2018 15:55:20 -0800 Subject: [PATCH] Fix crash on umd and module merge, allow umds to be accessed when merged with a non-UMD symbol --- src/compiler/checker.ts | 13 +++---- .../exportAsNamespace_augment.errors.txt | 14 +------- .../reference/umdGlobalAugmentationNoCrash.js | 27 ++++++++++++++ .../umdGlobalAugmentationNoCrash.symbols | 34 ++++++++++++++++++ .../umdGlobalAugmentationNoCrash.types | 36 +++++++++++++++++++ .../compiler/umdGlobalAugmentationNoCrash.ts | 21 +++++++++++ 6 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 tests/baselines/reference/umdGlobalAugmentationNoCrash.js create mode 100644 tests/baselines/reference/umdGlobalAugmentationNoCrash.symbols create mode 100644 tests/baselines/reference/umdGlobalAugmentationNoCrash.types create mode 100644 tests/cases/compiler/umdGlobalAugmentationNoCrash.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b0c22b6134..c163014b2b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1569,7 +1569,8 @@ namespace ts { // If we're in an external module, we can't reference value symbols created from UMD export declarations if (result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value && !(originalLocation!.flags & NodeFlags.JSDoc)) { - if (some(result.declarations, d => isNamespaceExportDeclaration(d) || isSourceFile(d) && !!d.symbol.globalExports)) { + const merged = getMergedSymbol(result); + if (length(merged.declarations) && every(merged.declarations, d => isNamespaceExportDeclaration(d) || isSourceFile(d) && !!d.symbol.globalExports)) { error(errorLocation!, Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, unescapeLeadingUnderscores(name)); // TODO: GH#18217 } } @@ -5322,12 +5323,11 @@ namespace ts { return anyType; } // Handle export default expressions - if (isSourceFile(declaration)) { - const jsonSourceFile = cast(declaration, isJsonSourceFile); - if (!jsonSourceFile.statements.length) { + if (isSourceFile(declaration) && isJsonSourceFile(declaration)) { + if (!declaration.statements.length) { return emptyObjectType; } - const type = getWidenedLiteralType(checkExpression(jsonSourceFile.statements[0].expression)); + const type = getWidenedLiteralType(checkExpression(declaration.statements[0].expression)); if (type.flags & TypeFlags.Object) { return getRegularTypeOfObjectLiteral(type); } @@ -5352,7 +5352,8 @@ namespace ts { || isClassDeclaration(declaration) || isFunctionDeclaration(declaration) || (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration)) - || isMethodSignature(declaration)) { + || isMethodSignature(declaration) + || isSourceFile(declaration)) { // Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty` if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) { return getTypeOfFuncClassEnumModule(symbol); diff --git a/tests/baselines/reference/exportAsNamespace_augment.errors.txt b/tests/baselines/reference/exportAsNamespace_augment.errors.txt index ba1b4d80c6..5e60df3bbb 100644 --- a/tests/baselines/reference/exportAsNamespace_augment.errors.txt +++ b/tests/baselines/reference/exportAsNamespace_augment.errors.txt @@ -1,10 +1,6 @@ /a.d.ts(3,14): error TS2451: Cannot redeclare block-scoped variable 'conflict'. /b.ts(6,22): error TS2451: Cannot redeclare block-scoped variable 'conflict'. /b.ts(12,18): error TS2451: Cannot redeclare block-scoped variable 'conflict'. -/b.ts(15,1): error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead. -/b.ts(15,7): error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead. -/b.ts(15,13): error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead. -/b.ts(15,19): error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead. ==== /a.d.ts (1 errors) ==== @@ -16,7 +12,7 @@ !!! related TS6203 /b.ts:6:22: 'conflict' was also declared here. !!! related TS6204 /b.ts:12:18: and here. -==== /b.ts (6 errors) ==== +==== /b.ts (2 errors) ==== import * as a2 from "./a"; declare global { @@ -38,13 +34,5 @@ } a.x + a.y + a.z + a.conflict; - ~ -!!! error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead. - ~ -!!! error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead. - ~ -!!! error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead. - ~ -!!! error TS2686: 'a' refers to a UMD global, but the current file is a module. Consider adding an import instead. a2.x + a2.y + a2.z + a2.conflict; \ No newline at end of file diff --git a/tests/baselines/reference/umdGlobalAugmentationNoCrash.js b/tests/baselines/reference/umdGlobalAugmentationNoCrash.js new file mode 100644 index 0000000000..23c2344a33 --- /dev/null +++ b/tests/baselines/reference/umdGlobalAugmentationNoCrash.js @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/umdGlobalAugmentationNoCrash.ts] //// + +//// [global.d.ts] +declare global { + const React: typeof import("./module"); +} +export {}; + +//// [module.d.ts] +export as namespace React; +export function foo(): string; + +//// [some_module.ts] +export {} +React.foo; + +//// [emits.ts] +console.log("hello"); +React.foo; + + +//// [some_module.js] +React.foo; +//// [emits.js] +"use strict"; +console.log("hello"); +React.foo; diff --git a/tests/baselines/reference/umdGlobalAugmentationNoCrash.symbols b/tests/baselines/reference/umdGlobalAugmentationNoCrash.symbols new file mode 100644 index 0000000000..ac3f57f2d5 --- /dev/null +++ b/tests/baselines/reference/umdGlobalAugmentationNoCrash.symbols @@ -0,0 +1,34 @@ +=== tests/cases/compiler/global.d.ts === +declare global { +>global : Symbol(global, Decl(global.d.ts, 0, 0)) + + const React: typeof import("./module"); +>React : Symbol("tests/cases/compiler/module", Decl(module.d.ts, 0, 0), Decl(global.d.ts, 1, 9)) +} +export {}; + +=== tests/cases/compiler/module.d.ts === +export as namespace React; +>React : Symbol(React, Decl(module.d.ts, 0, 0)) + +export function foo(): string; +>foo : Symbol(foo, Decl(module.d.ts, 0, 26)) + +=== tests/cases/compiler/some_module.ts === +export {} +React.foo; +>React.foo : Symbol(foo, Decl(module.d.ts, 0, 26)) +>React : Symbol("tests/cases/compiler/module", Decl(module.d.ts, 0, 0), Decl(global.d.ts, 1, 9)) +>foo : Symbol(foo, Decl(module.d.ts, 0, 26)) + +=== tests/cases/compiler/emits.ts === +console.log("hello"); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) + +React.foo; +>React.foo : Symbol(foo, Decl(module.d.ts, 0, 26)) +>React : Symbol("tests/cases/compiler/module", Decl(module.d.ts, 0, 0), Decl(global.d.ts, 1, 9)) +>foo : Symbol(foo, Decl(module.d.ts, 0, 26)) + diff --git a/tests/baselines/reference/umdGlobalAugmentationNoCrash.types b/tests/baselines/reference/umdGlobalAugmentationNoCrash.types new file mode 100644 index 0000000000..92643f4758 --- /dev/null +++ b/tests/baselines/reference/umdGlobalAugmentationNoCrash.types @@ -0,0 +1,36 @@ +=== tests/cases/compiler/global.d.ts === +declare global { +>global : typeof global + + const React: typeof import("./module"); +>React : typeof import("tests/cases/compiler/module") +} +export {}; + +=== tests/cases/compiler/module.d.ts === +export as namespace React; +>React : typeof import("tests/cases/compiler/module") + +export function foo(): string; +>foo : () => string + +=== tests/cases/compiler/some_module.ts === +export {} +React.foo; +>React.foo : () => string +>React : typeof import("tests/cases/compiler/module") +>foo : () => string + +=== tests/cases/compiler/emits.ts === +console.log("hello"); +>console.log("hello") : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>"hello" : "hello" + +React.foo; +>React.foo : () => string +>React : typeof import("tests/cases/compiler/module") +>foo : () => string + diff --git a/tests/cases/compiler/umdGlobalAugmentationNoCrash.ts b/tests/cases/compiler/umdGlobalAugmentationNoCrash.ts new file mode 100644 index 0000000000..ce0e0aae00 --- /dev/null +++ b/tests/cases/compiler/umdGlobalAugmentationNoCrash.ts @@ -0,0 +1,21 @@ +// @strict: true +// @module: esnext +// @moduleResolution: node +// @target: es2018 +// @filename: global.d.ts +declare global { + const React: typeof import("./module"); +} +export {}; + +// @filename: module.d.ts +export as namespace React; +export function foo(): string; + +// @filename: some_module.ts +export {} +React.foo; + +// @filename: emits.ts +console.log("hello"); +React.foo;